Browse Source

datafiles: tests

aguryev 3 years ago
parent
commit
1fd35d4a04

+ 0 - 0
files/tests/__init__.py


+ 309 - 0
files/tests/conftest.py

@@ -0,0 +1,309 @@
+import os
+#import tempfile
+import pytest
+from app import app#, db, models
+#import json
+#from random import randrange
+from tests.supports import path_to_data
+#import uuid
+
+#
+# common data
+#
+#path_to_data = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'data')
+
+@pytest.fixture
+def application():
+    #
+    # flask app 
+    #
+
+    return app
+
+@pytest.fixture
+def client():
+    #
+    # test client for application
+    #
+
+    return app.test_client()
+
+@pytest.fixture
+def uploads():
+    #
+    # upload folder
+    #
+
+    return app.config.get('UPLOAD_FOLDER')
+
+'''
+@pytest.fixture
+def database():
+    #
+    # test application db entity
+    #
+
+    # create temporal sqlite db file
+    db_filehandler, db_path = tempfile.mkstemp()
+    app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}'
+    app.config['TESTING'] = True
+
+    db.create_all()
+
+    yield db
+
+    db.session.remove()
+    db.drop_all()
+
+    os.close(db_filehandler)
+    os.unlink(db_path)
+
+#
+# fixture to support testing db dialect compatibiliries
+@pytest.fixture
+def db_dialect(db_url):
+    app.config['SQLALCHEMY_DATABASE_URI'] = db_url
+    app.config['TESTING'] = True
+
+    yield db
+#### NEED TO BE IMPOVED
+
+
+@pytest.fixture
+def application(database):
+    #
+    # test application
+    #
+
+    return database.get_app()
+
+@pytest.fixture
+def session(database):
+    #
+    # test db session
+    #
+
+    return database.session
+
+
+
+@pytest.fixture
+def test_user(session):
+    #
+    # creates test user in db
+    #
+
+    passwor_length = 7
+
+    user_data = {
+        'username': 'test',
+        'password': generate_password(),
+    }
+
+    user = models.User(username=user_data.get('username'))
+    user.set_password(user_data.get('password'))
+    session.add(user)
+    session.commit()
+
+    return user_data
+
+@pytest.fixture
+def db_supports(session):
+    #
+    # creates test support entities in db
+    #
+
+    supports_classes = {
+        'class-name': models.ClassName,
+        'browser-type': models.BrowserType,
+        'testcase-type': models.TestCaseType,
+        'activity-type': models.ActivityType,
+        'locator-type': models.LocatorType,
+    }
+
+    def _method(number_of_supports):
+        for classtag, classname in supports_classes.items():
+            for i in range(number_of_supports):
+                item = classname(name=f'{classtag}-{i+1}', description=f'Description of {classtag} {i+1}')
+                session.add(item)
+
+        session.commit()
+        return number_of_supports
+
+    return _method
+
+@pytest.fixture
+def default_supports(session):
+    #
+    # creates support instances to test rendering default values 
+    #
+
+    with open(os.path.join(path_to_data, 'default_supports.json'), 'r') as f:
+        instances = json.load(f)
+
+    for key, value in instances.items():
+        name = key.split('_')[0] 
+        if name == 'CLASSNAME':
+            support = models.ClassName(name=value, description=f'Test {key}')
+        elif name == 'BROWSER':
+            support = models.BrowserType(name=value, description=f'Test {key}')
+        elif name == 'TESTCASE':
+            support = models.TestCaseType(name=value, description=f'Test {key}')
+        elif name == 'ACTIVITY':
+            support = models.ActivityType(name=value, description=f'Test {key}')
+        elif name == 'LOCATOR':
+            support = models.LocatorType(name=value, description=f'Test {key}')
+        else:
+            raise Exception(f'Model class {name} is not supported')
+
+        session.add(support)
+    session.commit()
+
+    return instances
+
+@pytest.fixture
+def teststep_selects():
+    #
+    # available values of TestStep select fields
+    #
+
+    with open(os.path.join(path_to_data, 'teststep_selects.json'), 'r') as f:
+        return json.load(f)
+
+@pytest.fixture
+def testrun_import():
+    #
+    # imported testrun data
+    #
+
+    with open(os.path.join(path_to_data, 'testrun_simple.json'), 'r') as f:
+        return json.load(f)
+
+
+@pytest.fixture
+@pytest.mark.parametrize('db_supports', [3])
+def populate(session, test_user, db_supports, count):
+    #
+    # creates items for tests
+    # count = (x, y)
+    # x - number of testrun items
+    # y - number of child items of each created item 
+    #
+
+    number_of_supports = db_supports(3)
+
+    # Testrun objects
+    for tr in range(count[0]):
+        testrun = models.Testrun(
+            name=f'Test Testrun-{tr}',
+            description=f'Test Run-{tr} Description',
+            creator_id=1,
+        )
+        if count[0] == 1:
+            testrun.global_settings = '{"TC.BrowserAttributes": {"HEADLESS": "True"}}'
+        session.add(testrun)
+
+        # TestCaseSequence object
+        for tcs in range(count[1]):
+            testcase_sequence = models.TestCaseSequence(
+                name=f'Test TestCaseSequence-{tcs}',
+                description=f'Test TestCaseSequence-{tcs} Description',
+                classname_id=randrange(number_of_supports)+1,
+                creator_id=1,
+                testrun=[testrun],
+            )
+            session.add(testcase_sequence)
+
+            # DataFile object
+            datafile = models.DataFile(
+                filename=f'test_datafile_{tcs}',
+                sheet='test_sheet',
+                creator_id=1,
+                testcase_sequence=[testcase_sequence],
+            )
+            session.add(datafile)
+
+            # TestCase object
+            for tc in range(count[1]):
+                testcase = models.TestCase(
+                    name=f'Test TestCase-{tc}',
+                    description=f'Test TestCase-{tc} Description',
+                    classname_id=randrange(number_of_supports)+1,
+                    browser_type_id=randrange(number_of_supports)+1,
+                    testcase_type_id=randrange(number_of_supports)+1,
+                    creator_id=1,
+                    testcase_sequence=[testcase_sequence],
+                )
+                session.add(testcase)
+
+                # TestStepSequence object
+                for tss in range(count[1]): 
+                    teststep_sequence = models.TestStepSequence(
+                        name=f'Test TestStepSequence-{tss}',
+                        description=f'Test TestStepSequence-{tss} Description',
+                        classname_id=randrange(number_of_supports)+1,
+                        creator_id=1,
+                        testcase=[testcase],
+                    )
+                    session.add(teststep_sequence)
+
+                    # TestStepExecution object
+                    for ts in range(count[1]):
+                        teststep = models.TestStepExecution(
+                            name=f'Test TestStep-{ts}',
+                            description=f'Test TestStep-{ts} Description',
+                            activity_type_id=randrange(number_of_supports)+1,
+                            creator_id=1,
+                            teststep_sequence=teststep_sequence,
+                        )
+                        if count[1] == 1:
+                            # fill all fields
+                            teststep.locator_type_id = randrange(number_of_supports) + 1
+                            teststep.locator = 'test locator'
+                            teststep.optional = True
+                            teststep.timeout = 7.30
+                            teststep.release = 'v-test'
+                            teststep.value = 'test value'
+                            teststep.value2 = 'another test value'
+                            teststep.comparison = '<>'
+
+                        session.add(teststep)
+
+    # extra free steps: 3
+    if count[0] == 1:
+        for i in range(3):
+            teststep = models.TestStepExecution(
+                name='Free Test TestStep',
+                description=f'Free Test TestStep-{i} Description',
+                activity_type_id=randrange(number_of_supports)+1,
+                creator_id=1,
+            )
+            session.add(teststep)
+
+    session.commit()
+    return count
+
+@pytest.fixture
+def set_tr_calls(session, test_user):
+    #
+    # creates calls:dict for the testrun
+    #
+
+    def _method(tr_id, calls):
+        for call in calls:
+            # create call
+            tr_call = models.TestRunCall(
+                id=uuid.uuid4().bytes,
+                creator_id=1,
+                testrun_id=tr_id,
+            )
+            session.add(tr_call)
+
+            # set attributes
+            for key, value in call.items():
+                setattr(tr_call, key, value)
+
+        session.commit()
+
+    return _method
+'''

BIN
files/tests/data/datafile_1.xlsx


BIN
files/tests/data/datafile_2.xlsx


+ 1 - 0
files/tests/data/datafile_fake.xlsx

@@ -0,0 +1 @@
+fake data

+ 137 - 0
files/tests/supports.py

@@ -0,0 +1,137 @@
+from lxml import html
+from random import randrange
+import os# import path, remove
+
+# path to data
+path_to_data = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'data')
+
+'''
+item_data = {
+    'name': 'Test Item Name',
+    'description': 'Test Item Description',
+}
+
+# supplementary
+def dump_html(r):
+    #
+    # dumps response data to test.html
+    #
+
+    with open('test.html', 'w') as f:
+        f.write(r.data.decode())
+
+#
+# support functions 
+#
+def login(client, user):
+    #
+    # login to web system
+    #
+  
+    # login
+    r = client.post('/login', data={
+        'csrf_token': get_csrf(client, '/login'),
+        'username': user.get('username'),
+        'password': user.get('password'),
+    })
+
+def logout(client):
+    #
+    # logout web system
+    #
+
+    client.get('/logout')
+
+def get_csrf(client, url):
+    #
+    # get csrf_token for $url page
+    #
+
+    r = client.get(url)
+    page = html.fromstring(r.data)
+
+    return page.xpath('//input[@id="csrf_token"]')[0].value
+
+def generate_password(length=7):
+    return ''.join([chr(randrange(33, 127)) for i in range(length)])
+
+def remove_file(path_to_file):
+    try:
+        os.remove(path_to_file)
+    except:
+        raise Exception(f'Test file does not exist: {path_to_file}')
+
+def get_datafile_url(config, datafile_id):
+    return '/'.join((
+        'http:/',
+        config.get('BAANGT_DATAFILE_HOST'),
+        config.get('BAANGT_DATAFILE_GET'),
+        datafile_id,
+    ))
+
+
+class TRTestHelper:
+    TCS = 0
+    TC = 1
+    TSS = 2
+    TS = 3
+
+    def __init__(self, testrun):
+        self.tr = testrun
+
+    def get_num(self, layer):
+        #
+        # returns number of all abjects on the layer 
+        #
+
+        if layer == self.TCS:
+            return len(self.tr.testcase_sequences)
+
+        counter = 0
+        # TestCaseSequence
+        for tcs in self.tr.testcase_sequences:
+            # TestCase
+            for tc in tcs.testcases:
+                if layer == self.TC:
+                    counter += 1
+                else:
+                    # TestStep
+                    for tss in tc.teststep_sequences:
+                        if layer == self.TSS:
+                            counter += 1
+                        else:
+                            # TestStepExecution
+                            for ts in tss.teststeps:
+                                counter += 1
+        return counter
+
+    def get_indexes(self, layer):
+        #
+        # returns tuple of indexes and layer 
+        #
+
+        # child indexes
+        tc_index, tss_index, ts_index = 0, 0, 0
+
+        # TestCaseSequence
+        for tcs_index, tcs in enumerate(self.tr.testcase_sequences, 1):
+            if layer == self.TCS:
+                yield tcs_index, tcs
+            else:
+                # TestCase
+                for tc in tcs.testcases:
+                    tc_index += 1
+                    if layer == self.TC:
+                        yield tcs_index, tc_index, tc
+                    else:
+                        # TestStep
+                        for tss in tc.teststep_sequences:
+                            tss_index += 1
+                            if layer == self.TSS:
+                                yield tcs_index, tc_index, tss_index, tss
+                            else: 
+                                # TestStepExecution
+                                for ts in tss.teststeps:
+                                    ts_index += 1
+                                    yield tcs_index, tc_index, tss_index, ts_index, ts
+'''

+ 104 - 0
files/tests/test_routes.py

@@ -0,0 +1,104 @@
+
+from tests.supports import path_to_data
+import os
+import json
+import uuid
+
+#
+# GET home
+#
+def test_index(client):
+    r = client.get('/')
+    assert r.status_code == 200, f'status code: {r.status_code}'
+
+def test_save(application):
+    # set-up
+    url = '/save'
+    client = application.test_client()
+
+    # GET method
+    r = client.get(url)
+    assert r.status_code == 405, f'GET method. Status code: {r.status_code}'
+
+    # POST method without data
+    r = client.post(url)
+    assert r.status_code == 400, f'POST method withou data. Status code: {r.status_code}'
+    # assert error in response
+    response = json.loads(r.data)
+    assert 'error' in response
+
+    # POST method with wrong data
+    with open(os.path.join(path_to_data, 'datafile_1.xlsx'), 'rb') as f:
+        r = client.post(url, data={'file': f})
+    assert r.status_code == 400, f'POST method with wrong data. Status code: {r.status_code}'
+    # assert error in response
+    response = json.loads(r.data)
+    assert 'error' in response
+
+    # POST method with correct data
+    with open(os.path.join(path_to_data, 'datafile_1.xlsx'), 'rb') as f:
+        r = client.post(url, data={'dataFile': f})
+    assert r.status_code == 200
+    # assert response
+    response = json.loads(r.data)
+    assert 'uuid' in response
+    try:
+        uuid.UUID(response.get('uuid'))
+    except Exception as e:
+        assert False, f'Exception: {e}'
+    
+    # assert uploaded file
+    path_to_file = os.path.join(
+        application.root_path,
+        application.config.get('UPLOAD_FOLDER'),
+        response.get('uuid'),
+    )
+    assert os.path.isfile(path_to_file), 'Uploaded file does NOT exists in UPLOADS'
+
+    # remove uploaded file
+    os.remove(path_to_file)
+
+def test_update(application):
+    # set-up
+    file_id = uuid.uuid4()
+    url = f'/update/{file_id}'
+    client = application.test_client()
+
+    # GET method
+    r = client.get(url)
+    assert r.status_code == 405 f'GET method. Status code: {r.status_code}'
+
+    # POST method without data
+    r = client.post(url)
+    assert r.status_code == 400, f'POST method withou data. Status code: {r.status_code}'
+    # assert error in response
+    response = json.loads(r.data)
+    assert 'error' in response
+
+    # POST method with wrong data
+    with open(os.path.join(path_to_data, 'datafile_1.xlsx'), 'rb') as f:
+        r = client.post(url, data={'file': f})
+    assert r.status_code == 400 f'POST method with wrong data. Status code: {r.status_code}'
+    # assert error in response
+    response = json.loads(r.data)
+    assert 'error' in response
+
+    # POST method with correct data
+    with open(os.path.join(path_to_data, 'datafile_1.xlsx'), 'rb') as f:
+        r = client.post(url, data={'dataFile': f})
+    assert r.status_code == 200
+    # assert response
+    response = json.loads(r.data)
+    assert 'uuid' in response
+    assert response.get('uuid') == str(file_id), 'Response file ID does not match'
+    
+    # assert uploaded file
+    path_to_file = os.path.join(
+        application.root_path,
+        application.config.get('UPLOAD_FOLDER'),
+        str(file_id),
+    )
+    assert os.path.isfile(path_to_file), 'Uploaded file does NOT exists in UPLOADS'
+
+    # remove uploaded file
+    os.remove(path_to_file)