summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/tests/functional/functional_helpers.py
blob: 7c20437d148f53907c44d967fb895bf36529c3c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#! /usr/bin/env python3
#
# BitBake Toaster functional tests implementation
#
# Copyright (C) 2017 Intel Corporation
#
# SPDX-License-Identifier: GPL-2.0-only
#

import os
import logging
import subprocess
import signal
import re

from tests.browser.selenium_helpers_base import SeleniumTestCaseBase
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException

logger = logging.getLogger("toaster")
toaster_processes = []

class SeleniumFunctionalTestCase(SeleniumTestCaseBase):
    wait_toaster_time = 10

    @classmethod
    def setUpClass(cls):
        # So that the buildinfo helper uses the test database'
        if os.environ.get('DJANGO_SETTINGS_MODULE', '') != \
            'toastermain.settings_test':
            raise RuntimeError("Please initialise django with the tests settings:  "
                "DJANGO_SETTINGS_MODULE='toastermain.settings_test'")

        # Wait for any known toaster processes to exit
        global toaster_processes
        for toaster_process in toaster_processes:
            try:
                os.waitpid(toaster_process, os.WNOHANG)
            except ChildProcessError:
                pass

        # start toaster
        cmd = "bash -c 'source toaster start'"
        start_process = subprocess.Popen(
            cmd,
            cwd=os.environ.get("BUILDDIR"),
            shell=True)
        toaster_processes = [start_process.pid]
        if start_process.wait() != 0:
            port_use = os.popen("lsof -i -P -n | grep '8000 (LISTEN)'").read().strip()
            message = ''
            if port_use:
                process_id = port_use.split()[1]
                process = os.popen(f"ps -o cmd= -p {process_id}").read().strip()
                message = f"Port 8000 occupied by {process}"
            raise RuntimeError(f"Can't initialize toaster. {message}")

        builddir = os.environ.get("BUILDDIR")
        with open(os.path.join(builddir, '.toastermain.pid'), 'r') as f:
            toaster_processes.append(int(f.read()))
        with open(os.path.join(builddir, '.runbuilds.pid'), 'r') as f:
            toaster_processes.append(int(f.read()))

        super(SeleniumFunctionalTestCase, cls).setUpClass()
        cls.live_server_url = 'http://localhost:8000/'

    @classmethod
    def tearDownClass(cls):
        super(SeleniumFunctionalTestCase, cls).tearDownClass()

        global toaster_processes

        cmd = "bash -c 'source toaster stop'"
        stop_process = subprocess.Popen(
            cmd,
            cwd=os.environ.get("BUILDDIR"),
            shell=True)
        # Toaster stop has been known to hang in these tests so force kill if it stalls
        try:
            if stop_process.wait(cls.wait_toaster_time) != 0:
                raise Exception('Toaster stop process failed')
        except Exception as e:
            if e is subprocess.TimeoutExpired:
                print('Toaster stop process took too long. Force killing toaster...')
            else:
                print('Toaster stop process failed. Force killing toaster...')
            stop_process.kill()
            for toaster_process in toaster_processes:
                os.kill(toaster_process, signal.SIGTERM)


    def get_URL(self):
         rc=self.get_page_source()
         project_url=re.search(r"(projectPageUrl\s:\s\")(.*)(\",)",rc)
         return project_url.group(2)


    def find_element_by_link_text_in_table(self, table_id, link_text):
        """
        Assume there're multiple suitable "find_element_by_link_text".
        In this circumstance we need to specify "table".
        """
        try:
            table_element = self.get_table_element(table_id)
            element = table_element.find_element(By.LINK_TEXT, link_text)
        except NoSuchElementException:
            print('no element found')
            raise
        return element

    def get_table_element(self, table_id, *coordinate):
        if len(coordinate) == 0:
#return whole-table element
            element_xpath = "//*[@id='" + table_id + "']"
            try:
                element = self.driver.find_element(By.XPATH, element_xpath)
            except NoSuchElementException:
                raise
            return element
        row = coordinate[0]

        if len(coordinate) == 1:
#return whole-row element
            element_xpath = "//*[@id='" + table_id + "']/tbody/tr[" + str(row) + "]"
            try:
                element = self.driver.find_element(By.XPATH, element_xpath)
            except NoSuchElementException:
                return False
            return element
#now we are looking for an element with specified X and Y
        column = coordinate[1]

        element_xpath = "//*[@id='" + table_id + "']/tbody/tr[" + str(row) + "]/td[" + str(column) + "]"
        try:
            element = self.driver.find_element(By.XPATH, element_xpath)
        except NoSuchElementException:
            return False
        return element