Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development selenium add stats page tests 1 #3313

Open
wants to merge 16 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/playground/tests/frontend_selenium/Config.ini
Marinaa-Emad marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
port = 5173
net = dev
[Utils]
seed =
A-Harby marked this conversation as resolved.
Show resolved Hide resolved
node_seed =
address =
email =
seed = hobby minor mule problem action bomb eye frown coil lunch runway caution
node_seed = thank crowd vintage story arrow fantasy this spray speed cherry snow water
address = GAK2AN6ZC4REV2GXZPTMJG2JKLRJQX746JNG7ACKNC4RSJE7ETAZSE7D
email = [email protected]
87 changes: 87 additions & 0 deletions packages/playground/tests/frontend_selenium/pages/statistics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException



class StatisticsPage:

logout_button = (By.XPATH, "//button[.//span[text()=' Logout ']]")
tfgrid_button = (By.XPATH, "//span[text()='TFGrid']")
grid_status_button = (By.XPATH, "//span[text()='Grid Status']")
node_monitoring_button = (By.XPATH, "//span[text()='Node Monitoring']")
statistics_button = (By.XPATH, "//span[text()='Node Statistics']")
statistics_label = (By.XPATH, "//*[contains(text(), 'Statistics')]")
map= (By.XPATH,"//button[contains(@class, 'btn-main-container')]")
nodes_online = (By.XPATH, "//span[text()='Nodes Online']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
dedicated_machines = (By.XPATH, "//span[text()='Dedicated Machines']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
farms = (By.XPATH, "//span[text()='Farms']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
countries = (By.XPATH, "//span[text()='Countries']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
cpus = (By.XPATH, "//span[text()='CPUs']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
ssd_storage = (By.XPATH, "//span[text()='SSD Storage']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
hdd_storage = (By.XPATH, "//span[text()='HDD Storage']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
ram = (By.XPATH, "//span[text()='RAM']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
gpus = (By.XPATH, "//span[text()='GPUs']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
access_nodes = (By.XPATH, "//span[text()='Access Nodes']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
gateways = (By.XPATH, "//span[text()='Gateways']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
twins = (By.XPATH, "//span[text()='Twins']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
public_ips = (By.XPATH, "//span[text()='Public IPs']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
conracts = (By.XPATH, "//span[text()='Contracts']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")
number_of_workloads = (By.XPATH, "//span[text()='Number of workloads']/ancestor::div/following-sibling::div[@class='v-card-text card-body']")


def __init__(self, browser):
self.browser = browser
def navigate(self):
webdriver.ActionChains(self.browser).send_keys(Keys.ESCAPE).perform()
self.browser.find_element(*self.tfgrid_button).click()
self.browser.find_element(*self.statistics_button).click()
WebDriverWait(self.browser, 60).until(EC.visibility_of_element_located(self.statistics_label))
def statistics_detials(self):
details = []
wait = WebDriverWait(self.browser, 60) # Increased wait time to 60 seconds
elements_to_fetch = [
("Nodes Online", self.nodes_online),
("Dedicated Machines", self.dedicated_machines),
("Farms", self.farms),
("Countries", self.countries),
("CPUs", self.cpus),
("SSD Storage", self.ssd_storage),
("HDD Storage", self.hdd_storage),
("RAM", self.ram),
("GPUs", self.gpus),
("Access Nodes", self.access_nodes),
("Gateways", self.gateways),
("Twins", self.twins),
("Public IPs", self.public_ips),
("Contracts", self.conracts),
("Number of workloads", self.number_of_workloads)
]
try:
for name, locator in elements_to_fetch:
try:
element_text = wait.until(EC.visibility_of_element_located(locator)).text
details.append(element_text)
print(f"{name} fetched: {element_text}")
except TimeoutException:
print(f"{name} not found within the specified time.")
details.append(None)# Add None or some default value to maintain list consistency
except TimeoutException as e:
print(f"TimeoutException: {e}")
return details
def get_link(self):
WebDriverWait(self.browser, 30).until(EC.number_of_windows_to_be(2))
self.browser.switch_to.window(self.browser.window_handles[1])
url = self.browser.current_url
self.browser.close()
self.browser.switch_to.window(self.browser.window_handles[0])
return url
def grid_status_link(self):
self.browser.find_element(*self.grid_status_button).click()
return self.get_link()
def node_monitoring_link(self):
self.browser.find_element(*self.node_monitoring_button).click()
return self.get_link()
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import math
from utils.utils import byte_converter,convert_to_scaled_float
from pages.statistics import StatisticsPage
from utils.grid_proxy import GridProxy
from pages.dashboard import DashboardPage

def before_test_setup(browser):
statistics_page = StatisticsPage(browser)
dashboard_page = DashboardPage(browser)
dashboard_page.open_and_load()
statistics_page.navigate()
return statistics_page

def test_statistics_details(browser):
statistics_page = before_test_setup(browser)
grid_proxy = GridProxy(browser)
statistics_details = statistics_page.statistics_detials()
print("Statistics Details:", statistics_details)
grid_statistics_details = grid_proxy.get_stats()
# Convert necessary values from string to integer before comparing
statistics_details_converted = [int(detail.replace(',', '')) if detail is not None and detail.isdigit() else detail for detail in statistics_details]
# Full set of assertions, comparing UI stats with proxy stats
assert grid_statistics_details['nodes'] == statistics_details_converted[0]
assert grid_statistics_details['dedicatedNodes'] == statistics_details_converted[1]
assert grid_statistics_details['farms'] == statistics_details_converted[2]
assert grid_statistics_details['countries'] == statistics_details_converted[3]
assert grid_statistics_details['totalCru'] == statistics_details_converted[4]
assert math.isclose(convert_to_scaled_float(grid_statistics_details['totalSru']), convert_to_scaled_float(byte_converter(statistics_details_converted[5])), abs_tol=0.002)
assert math.isclose(convert_to_scaled_float(grid_statistics_details['totalHru']), convert_to_scaled_float(byte_converter(statistics_details_converted[6])), abs_tol=0.002)
assert math.isclose(convert_to_scaled_float(grid_statistics_details['totalMru']), convert_to_scaled_float(byte_converter(statistics_details_converted[7])), abs_tol=0.002)
assert grid_statistics_details['gpus'] == statistics_details_converted[8]
assert grid_statistics_details['accessNodes'] == statistics_details_converted[9]
assert grid_statistics_details['gateways'] == statistics_details_converted[10]
assert grid_statistics_details['twins'] == statistics_details_converted[11]
assert grid_statistics_details['publicIps'] == statistics_details_converted[12]
assert grid_statistics_details['contracts'] == statistics_details_converted[13]
assert grid_statistics_details['workloads_number'] == statistics_details_converted[14]
A-Harby marked this conversation as resolved.
Show resolved Hide resolved
assert statistics_page.grid_status_link() == 'https://status.grid.tf/status/threefold/'
assert statistics_page.node_monitoring_link() == 'https://metrics.grid.tf/d/rYdddlPWkfqwf/zos-host-metrics?orgId=2&refresh=30s/'
45 changes: 42 additions & 3 deletions packages/playground/tests/frontend_selenium/utils/grid_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,46 @@ def get_twin_node(self, twin_id):
details = r.json()
return details


def get_stats(self):
r = requests.post('https://stats.' + Base.net + '.grid.tf/api/stats-summary')
stats_json = r.json()
return list(stats_json.values())
up = requests.get(Base.gridproxy_url + 'stats?status=up', timeout=10).json()
standby = requests.get(Base.gridproxy_url + 'stats?status=standby', timeout=10).json()

# Initialize a dictionary to store the merged data
merged_data = {}

# Merge simple values, summing if they differ
keys_to_sum = ['nodes', 'accessNodes', 'totalCru', 'totalSru', 'totalMru', 'totalHru', 'gpus', 'dedicatedNodes', 'workloads_number']
for key in keys_to_sum:
merged_data[key] = up[key] + standby[key]

# Merge the "farms", "publicIps", "gateways", "twins", and "contracts" fields (they are the same)
keys_to_add_once = ['farms', 'publicIps', 'gateways', 'twins', 'contracts']
for key in keys_to_add_once:
merged_data[key] = up[key]

# Merge nodesDistribution and calculate unique and common countries
up_distribution = up['nodesDistribution']
standby_distribution = standby['nodesDistribution']

merged_distribution = {}
common_countries = 0

for country, up_count in up_distribution.items():
standby_count = standby_distribution.get(country, 0)
merged_distribution[country] = up_count + standby_count
if standby_count > 0:
common_countries += 1

for country, standby_count in standby_distribution.items():
if country not in merged_distribution:
merged_distribution[country] = standby_count

merged_data['nodesDistribution'] = merged_distribution

# Calculate the total countries: all unique countries minus common countries
total_countries = len(merged_distribution) # Total unique countries
merged_data['countries'] = total_countries

# Return the dictionary directly
return merged_data
23 changes: 18 additions & 5 deletions packages/playground/tests/frontend_selenium/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,16 +175,29 @@ def randomize_public_ipv4():
ip_subnet = ip + '/' + random.choice(['26', '27', '28', '29'])
return ip_subnet, ip


def convert_to_scaled_float(number):
str_number = str(number)
if '.' in str_number:
decimal_index = str_number.index('.')
else:
decimal_index = len(str_number)
divisor = 10 ** decimal_index
scaled_number = number / divisor
return scaled_number



def byte_converter(value):
A-Harby marked this conversation as resolved.
Show resolved Hide resolved
if value != '0':
if value[-2] == 'P':
return float(value[:-3])*(1024*2)
return float(value[:-3]) * (1024 ** 5)
elif value[-2] == 'T':
return float(value[:-3])*1024
else:
return float(value[:-3]) * (1024 ** 4)
elif value[-2] == 'G':
return float(value[:-3])
A-Harby marked this conversation as resolved.
Show resolved Hide resolved
else:
return float(value)
return float(value)


def get_min(nodes, resource):
min = nodes[0][resource]
Expand Down
10 changes: 10 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3334,6 +3334,11 @@
resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz"
integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==

"@types/semver@^7.5.8":
version "7.5.8"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==

"@types/[email protected]":
version "8.1.1"
resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3"
Expand Down Expand Up @@ -12647,6 +12652,11 @@ semver@^7.5.3, semver@^7.5.4:
dependencies:
lru-cache "^6.0.0"

semver@^7.6.2:
version "7.6.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==

semver@~7.0.0:
version "7.0.0"
resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz"
Expand Down