def test_round_hours(): """Test we round hours and minutes properly.""" assert 1 == round_hours(1, 0) assert 2 == round_hours(1, 1) assert 2 == round_hours(1, 59) assert 3 == round_hours(2, 60) assert 5 == round_hours(3, 61)
def test_reused_image(cloud_account_data, browser_session, ui_acct_list): """Multiple instances uses one image should be reflected properly.""" selenium = browser_session with return_url(selenium): events = [1, None] hours, spare_min, events = get_expected_hours_in_past_30_days(events) num_instances = randint(2, 5) hours = round_hours(hours * num_instances, spare_min * num_instances) ec2_ami_id = 'ami-{}'.format(randint(1000, 99999)) for _ in range(num_instances): cloud_account_data('rhel', events, ec2_ami_id=ec2_ami_id) selenium.refresh() account = find_element_by_text(selenium, CLOUD_ACCOUNT_NAME, timeout=0.5) assert find_element_by_text( selenium, f'{num_instances} Instances', exact=False) account.click() time.sleep(1) ctn = selenium.find_element_by_css_selector('.list-view-pf-main-info') hours_el = find_element_by_text(ctn, f'RHEL', exact=False) hours_txt = hours_el.get_attribute('innerText') assert find_element_by_text(selenium, ec2_ami_id, exact=False) label = f'{hours}RHEL' assert find_element_by_text(selenium, label, exact=False),\ f'"{hours} RHEL" expected; instead, saw "{hours_txt}"'
def test_image_tag(events, cloud_account_data, browser_session, ui_acct_list, tag): """Test that the account detail view displays correct tags for images. :id: 20b060c0-c2f4-4864-bb71-239720ceaa8f :description: Test the account detail view shows correct tags for images. :steps: 1) Given a user and cloud account, mock usage for an image. 2) Navigate to the account detail view. 3) Assert that the image is listed. 4) Assert that the image has the correct number of hours displayed. 5) Assert that the correct tags are displayed. :expectedresults: Image tags are displayed in the detail view and tags do not interfere with any listing of other data. """ selenium = browser_session instance_id = 'i-{}'.format(randint(1000, 99999)) ec2_ami_id = 'ami-{}'.format(randint(1000, 99999)) hours, spare_min, events = get_expected_hours_in_past_30_days(events) hours = round_hours(hours, spare_min) cloud_account_data( tag, events, instance_id=instance_id, ec2_ami_id=ec2_ami_id) selenium.refresh() assert find_element_by_text(selenium, '1 Instances', timeout=1) account = find_element_by_text(selenium, CLOUD_ACCOUNT_NAME, timeout=0.5) with return_url(selenium): account.click() time.sleep(1) # now in detail view # assert that product identification tags are correctly displayed rhel = 0 rhocp = 0 if 'rhel' in tag: rhel = hours if 'openshift' in tag: rhocp = hours assert find_element_by_text(selenium, f'{rhel}RHEL', exact=False) assert find_element_by_text(selenium, f'{rhocp}RHOCP', exact=False) assert find_element_by_text(selenium, ec2_ami_id, exact=False)
def test_hours_image(events, cloud_account_data, browser_session, ui_acct_list): """Test that the account detail view displays correct data for images. :id: 2f666f93-5844-4bfb-b0bf-e31f856657a3 :description: Test that the account detail view shows the detailed breakdown of hours used per image. :steps: 1) Given a user and cloud account, mock usage for an image. 2) Navigate to the account detail view. 3) Assert that the image is listed. 4) Assert that the image has the correct number of hours displayed. :expectedresults: The image used is listed in the detail view and has the hours used displayed correctly. """ selenium = browser_session instance_id = 'i-{}'.format(randint(1000, 99999)) ec2_ami_id = 'ami-{}'.format(randint(1000, 99999)) hours, spare_min, events = get_expected_hours_in_past_30_days(events) hours = round_hours(hours, spare_min) cloud_account_data( 'rhel', events, instance_id=instance_id, ec2_ami_id=ec2_ami_id, ) selenium.refresh() account = find_element_by_text(selenium, CLOUD_ACCOUNT_NAME, timeout=2) with return_url(selenium): account.click() time.sleep(1) assert find_element_by_text(selenium, ec2_ami_id, exact=False, timeout=0.5) info_bar = browser_session.find_element_by_css_selector( '.cloudmeter-list-view-card' ) assert find_element_by_text(info_bar, f'{hours}RHEL', exact=False), \ f'seen: {info_bar.get_attribute("innerText")}, ' \ f'expected: {hours} RHEL'
def test_running_tags(tag, cloud_account_data, browser_session, ui_acct_list): """Tags on images should not affect image or instance counts in summaries. :id: e9ea3960-051d-47cd-a23b-013ad8deb243 :description: The presence of tags should not affect image or instance counts, but should be reflected in the summaries themselves. :steps: 1) Add a cloud account 2) Create images and instances with no tag, each tag, and both tags :expectedresults: - The image and instance counts should always be 1 - The RHEL label should be 1 when the image has the rhel tag - The RHOCP label should be 1 when the image has the openshift tag - Both labels should be 1 when an image has both tags """ cloud_account_data(tag, [10]) hours, spare_min, events = get_expected_hours_in_past_30_days([10, None]) hours = round_hours(hours, spare_min) browser_session.refresh() assert find_element_by_text(browser_session, '1 Images', timeout=1) assert find_element_by_text(browser_session, '1 Instances') for level in ('summary', 'detail'): with return_url(browser_session): if level == 'detail': find_element_by_text(browser_session, 'First Account', timeout=1).click() time.sleep(1) if 'rhel' in tag: # No spaces because there are not spaces between the DOM nodes, # even tho they are rendered separately. assert find_element_by_text(browser_session, f'{hours}RHEL') else: assert find_element_by_text(browser_session, '0RHEL') if 'openshift' in tag: assert find_element_by_text(browser_session, f'{hours}RHOCP') else: assert find_element_by_text(browser_session, '0RHOCP')
def test_multiple_accounts( events, drop_account_data, ui_user, ui_dashboard, browser_session): """Test that having multiple accounts does not interfere with detail view. :id: 8bc0e630-2f52-4c73-a46d-355a7f79e339 :description: Test that having many accounts does not change how detail view works for a given individual account. :steps: 1) Given a user and several cloud accounts, mock usage for an image associated with one of the accounts. 2) Assert the accounts with no usage have no detail view. 3) Navigate to the account detail view of the active account. 4) Assert that the image is listed. 5) Assert that the image has the correct number of hours displayed. :expectedresults: Only accounts with usage have detail views and having multiple accounts does not degrade any use of the detail view. """ selenium = browser_session with return_url(selenium): ec2_ami_id = 'ami-{}'.format(randint(1000, 99999)) hours, spare_min, events = get_expected_hours_in_past_30_days(events) hours = round_hours(hours, spare_min) accts = [] num_accounts = 3 active_account_indx = randint(0, num_accounts - 1) # inject aws accounts for _ in range(num_accounts): name = 'cloud_account_{}'.format(randint(1000000, 999999999)) acct = inject_aws_cloud_account(ui_user['id'], name=name) accts.append(acct) selenium.refresh() time.sleep(1) # inject instance activity for the account account = accts[active_account_indx] inject_instance_data( account['id'], 'rhel', events, ec2_ami_id=ec2_ami_id ) selenium.refresh() time.sleep(1) for indx in range(len(accts)): acct = accts[indx] if indx != active_account_indx: account_bar = find_element_by_text(selenium, acct['name']) account_bar.click() assert find_element_by_text( selenium, 'No instances available', exact=False) account_bar = find_element_by_text(selenium, account['name']) assert account_bar account_bar.click() time.sleep(1) ctn = selenium.find_element_by_css_selector('.list-view-pf-main-info') hours_el = find_element_by_text(ctn, f'RHEL', exact=False) hours_txt = hours_el.get_attribute('innerText') assert find_element_by_text(ctn, ec2_ami_id, exact=False) label = f'{hours}RHEL' assert find_element_by_text(ctn, label, exact=False),\ f'"{hours} RHEL" expected; instead, saw "{hours_txt}"'
def test_flag_icons_on_challenged_accounts(cloud_account_data, browser_session, ui_acct_list): """Presence of flag icon should correlate across accounts and images. :id: DC7F8495-FDFE-4B55-8B95-858E8021FA7A :description: Check that flags ARE or ARE NOT present for accounts accurately representing the status of their images (challenged/not challenged) :steps: 1) Given a user with accounts, mock an account with images for each combination of RHEL / Openshift and disputed / undisputed. 2) Dispute images such that there are account instances of each of the following: Both RHEL and RHOCP, neither disputed Both RHEL and RHOCP, RHEL disputed Both RHEL and RHOCP, RHOCP disputed Both RHEL and RHOCP, both RHEL and RHOCP disputed :expectedresults: - Accounts with undisputed (non-flagged) images should have no flag - Accounts with a disputed (flagged) image should have a flag by the disputed image tag ('RHEL' or 'RHOCP') - Accounts with both RHEL and RHOCP disputes should have both flagged """ selenium = browser_session flagged = False instance_id = 'i-{}'.format(randint(1000, 99999)) ec2_ami_id = 'ami-{}'.format(randint(1000, 99999)) hours, spare_min, events = get_expected_hours_in_past_30_days([2, 1]) hours = round_hours(hours, spare_min) long_css_selector = '.cloudmeter-accountview-list-view-item' cloud_account_data( 'rhel', events, instance_id=instance_id, ec2_ami_id=ec2_ami_id, challenged=flagged, ) selenium.refresh() time.sleep(0.5) # There are no flags on the account when nothing has been challenged ctn = selenium.find_element_by_css_selector(long_css_selector) assert bool(ctn.find_elements_by_class_name('fa-flag')) == flagged account = find_element_by_text(selenium, CLOUD_ACCOUNT_NAME, timeout=0.5) with return_url(selenium): account.click() time.sleep(1) # Challenge current tag check = 'Flag for review' image_id_el = find_element_by_text(selenium, ec2_ami_id) image_id_el.click() time.sleep(0.1) find_element_by_text(selenium, check, selector='label').click() # Go back to accounts page and see that flagging matches # (currently one flagged) time.sleep(1) ctn = selenium.find_element_by_css_selector(long_css_selector) flags = ctn.find_elements_by_class_name('fa-flag') assert bool(flags) != flagged assert len(flags) == 1 # Challenge the other tag (so both are challenged) account = find_element_by_text(selenium, CLOUD_ACCOUNT_NAME, timeout=0.5) with return_url(selenium): account.click() time.sleep(1) image_id_el = find_element_by_text(selenium, ec2_ami_id) image_id_el.click() time.sleep(0.5) find_element_by_text(selenium, check, selector='label').click() # Go back to accounts page and see that flagging matches # (currently two flagged) time.sleep(1) ctn = selenium.find_element_by_css_selector(long_css_selector) flags = ctn.find_elements_by_class_name('fa-flag') assert bool(flags) != flagged assert len(flags) == 2 # Check flagging where 1 image flagged for RHEL and 1 other image # flagged for RHOCP # Create second image in same account second_ec2_ami_id = 'ami-{}'.format(randint(1000, 99999)) cloud_account_data( 'rhocp', [5], instance_id='i-{}'.format(randint(1000, 99999)), ec2_ami_id=second_ec2_ami_id, ) selenium.refresh() time.sleep(0.5) account = find_element_by_text(selenium, CLOUD_ACCOUNT_NAME, timeout=0.5) with return_url(selenium): account.click() time.sleep(1) # Unchallenge second flagged item in first image image_id_el = find_element_by_text(selenium, ec2_ami_id) image_id_el.click() time.sleep(0.5) find_element_by_text(selenium, 'Flagged for review', selector='label').click() time.sleep(1) image_id_el.click() time.sleep(0.5) # Challenge second item in second image second_image_id_el = find_element_by_text(selenium, second_ec2_ami_id) second_image_id_el.click() time.sleep(0.5) find_element_by_text(selenium, check, selector='label').click() # Go back to the accounts page and be sure that both are flagged time.sleep(1) ctn = selenium.find_element_by_css_selector(long_css_selector) flags = ctn.find_elements_by_class_name('fa-flag') assert len(flags) == 2
def test_image_flagging(cloud_account_data, browser_session, ui_acct_list, tag, flagged): """Flagging images should negate the detected states w/ proper indication. :id: 5c9b8d7c-9b0d-43b5-ab1a-220556adf99c :description: Test flagging both detected and undetected states for RHEL and Openshfit. :steps: 1) Given a user and cloud account, mock an image with some usage for each combination of RHEL and Openshift being detected or undetected by cloudigrade. 2) For each tag flag the detected state :expectedresults: - For either detected or undetected states the label should appear - Once flagged, a flag should be added - The graph should be updated with new data """ selenium = browser_session instance_id = 'i-{}'.format(randint(1000, 99999)) ec2_ami_id = 'ami-{}'.format(randint(1000, 99999)) hours, spare_min, events = get_expected_hours_in_past_30_days([2, 1]) hours = round_hours(hours, spare_min) cloud_account_data( tag, events, instance_id=instance_id, ec2_ami_id=ec2_ami_id, challenged=flagged, ) selenium.refresh() assert find_element_by_text(selenium, '1 Instances', timeout=1) account = find_element_by_text(selenium, CLOUD_ACCOUNT_NAME, timeout=0.5) with return_url(selenium): account.click() time.sleep(1) if 'rhel' == tag: label = 'RHEL' elif 'openshift' == tag: label = 'RHOCP' else: raise RuntimeError( 'Test did not expect tag parameter: %r' % (tag,) ) if flagged: check = 'Flagged for review' else: check = 'Flag for review' ctn = selenium.find_element_by_css_selector('.list-view-pf-main-info') assert product_id_tag_present(selenium, label) assert bool(ctn.find_elements_by_class_name('fa-flag')) == flagged image_id_el = find_element_by_text(selenium, ec2_ami_id) image_id_el.click() time.sleep(0.1) info = elem_parent( find_element_by_text(ctn, f'{label}', exact=False) ) tags_before = len(find_elements_by_text(ctn, label)) hours_before = get_el_text(info) find_element_by_text(selenium, check, selector='label').click() time.sleep(1) info = elem_parent( find_element_by_text(ctn, f'{label}', exact=False) ) tags_after = len(find_elements_by_text(ctn, label)) hours_after = get_el_text(info) assert bool(ctn.find_elements_by_class_name('fa-flag')) != flagged assert tags_after == tags_before assert hours_before != hours_after
def test_graph_modes(drop_account_data, cloud_account_data, browser_session, ui_acct_list): """Test the three "dimensions" of both RHEL and RHOCP usage. :id: 753b6e47-501a-4cae-af20-a8eece9ef50d :description: Usage of images is measured in instance hours, GB of memory per hour, and vCPU core per hour. RHEL graphs default to Instance Hours while RHOCP default to GB Memory Hours, both can be viewed for either. :steps: 1) Look at an account with both RHEL and RHOCP usage with instances of different types 2) Check the default type of each graph and that the value displayed matches 3) Change each of the graphs to their two non-default types, confirming each :expectedresults: - RHEL and RHOCP graphs should display Instance Hours and GB Memory Hours, respectively - Each graph can be changed to one of the other dimensions without affecting the other - Navigation returns to the default for each graph - GB Memory Hours displayed reflect the runtime of instances multiplied by the number of GB of the instance type - Core Hours displayed reflect the runtime of instances multiplied by the number of cores of the instance type """ cloud_account_data('rhel', [10], vcpu=2, memory=0.5) cloud_account_data('rhel,openshift', [5], vcpu=2, memory=0.5) cloud_account_data('openshift', [10], vcpu=4, memory=4) hours1, min1, events = get_expected_hours_in_past_30_days([10, None]) hours2, min2, events = get_expected_hours_in_past_30_days([5, None]) c = math.ceil # RHEL Hours for each "dimension" # image1 for 10 days + image2 for 5 days rhel_hours = { 'instance': round_hours(hours1 + hours2, min1 + min2), 'gb': round_hours(c((hours1 + hours2) / 2), c((min1 + min2) / 2)), 'cpu': round_hours(hours1 * 2 + hours2 * 2, min1 * 2 + min2 * 2), } # RHOCP, image2 for 5 days + image3 for 10 days rhocp_hours = { 'instance': round_hours(hours1 + hours2, min1 + min2), 'gb': round_hours(c(hours1 * 4 + hours2 / 2), c(min1 * 4 + min2 / 2)), 'cpu': round_hours(hours1 * 4 + hours2 * 2, min1 * 4 + min2 * 2), } browser_session.refresh() # Find the graph card based on the product header def graph_card(header): el = find_element_by_text( browser_session, header, ) el = el.find_element_by_xpath('..') el = el.find_element_by_xpath('..') return el for tag in ('RHEL', 'RHOCP'): # Establish expectations based on the current product if tag == 'RHEL': header = 'Red Hat Enterprise Linux' hours = rhel_hours dimensions = ( DIM_INSTANCE, DIM_MEMORY, DIM_VCPU, ) else: header = 'Red Hat OpenShift Container Platform' hours = rhocp_hours dimensions = ( DIM_VCPU, DIM_INSTANCE, DIM_MEMORY, ) # Check the graphs on both the summary and detail pages for level in ('summary', 'detail'): # For detail pages, navigate to the image list for the account # and return back afterwards with return_url(browser_session): if level == 'detail': find_element_by_text(browser_session, 'First Account', timeout=1).click() time.sleep(1) # Starting with the default dimension for this product, # walk through each via the dropdown menu on the appropriate # graph card and verify the numbers we see based on the # expected hours calculated above. for i, (dim, dropdown) in enumerate(dimensions): if i > 0: find_element_by_text(graph_card(header), dropdown, timeout=1).click() time.sleep(0.25) assert find_element_by_text(graph_card(header), f'{hours[dim]}{tag}', timeout=1) find_element_by_text(graph_card(header), dropdown, timeout=1).click()