-
Notifications
You must be signed in to change notification settings - Fork 294
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
test: E2E test case for the creation of the podman machine with user mode enabled #8528
base: main
Are you sure you want to change the base?
test: E2E test case for the creation of the podman machine with user mode enabled #8528
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just a comment on timeout
37cec22
to
d3bc498
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments.
d3bc498
to
ea31515
Compare
await pdRunner.close(); | ||
}); | ||
|
||
test.describe.serial('Rootless Podman machine Verification', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a need for this file in testing the user mode machine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it's not needed. I updated it because it prompted an error when testing it on GH Actions. If you have a different version you can substitute it completely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still working on that file and it's not on containers main yet, just my branch where I'm testing it, so you don't have to update it in your PR.
async handleConnectionDialog(machineName: string, setAsDefault: boolean): Promise<void> { | ||
const connectionDialog = this.page.getByRole('dialog', { name: 'Podman' }); | ||
const dialogMessage = connectionDialog.getByLabel('Dialog Message'); | ||
if ((await connectionDialog.isVisible()) && (await dialogMessage.isVisible())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was checking the regex of dialog message so I could be sure the connection dialog was regarding specifically the newly created machine, but if we don't want to check that we don't need to check the visibility of the dialog message if we know the dialog is already there.
} else { | ||
console.log(`Podman machine [${machineVisibleName}] not present, skipping deletion.`); | ||
} | ||
} | ||
|
||
export async function handleResetDefaultConnectionDialog(page: Page): Promise<void> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is defined but never used
isRootful: boolean = true, | ||
enableUserNet: boolean = false, | ||
startNow: boolean = true, | ||
setAsDefault: boolean = true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please refactor this to use object descructuring, these are too many optional params not to be descructured.
async isEnabled(checkbox: Locator): Promise<boolean> { | ||
await playExpect(checkbox).toBeVisible(); | ||
const upperElement = checkbox.locator('..').locator('..'); | ||
const clickableCheckbox = upperElement.getByText('Enabled'); | ||
return await clickableCheckbox.isVisible(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you not just check if the checkbox isChecked()?
async switchCheckbox(checkbox: Locator): Promise<void> { | ||
await playExpect(checkbox).toBeVisible(); | ||
const upperElement = checkbox.locator('..').locator('..'); | ||
|
||
const wasEnabled = await this.isEnabled(checkbox); | ||
let checkText; | ||
if (wasEnabled) { | ||
checkText = 'Enabled'; | ||
} else { | ||
checkText = 'Disabled'; | ||
} | ||
|
||
const clickableCheckbox = upperElement.getByText(checkText); | ||
await clickableCheckbox.click(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, the checkbox should be checkable for the isChecked() state.
if (await connectionDialog.isVisible()) { | ||
let handleButtonName = 'Yes'; | ||
if (!setAsDefault) { | ||
handleButtonName = 'Ignore'; | ||
} | ||
const handleButton = connectionDialog.getByRole('button', { name: handleButtonName }); | ||
await handleButton.click(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not the right way to check this, the method isVisible() always returns immediately, it has no innate waiter, as such it can return false just as easily as true, simply because of system lag, this is very flaky behavior.
await this.page.waitForTimeout(2_000); //wait for dialog to appear, in the needed cases | ||
await this.handleConnectionDialog(setAsDefault); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not the best approach, you should be waiting until the element that you need is available, I would say that in this case you should use await playExpect(setAsDefault).toBeVisible()
instead of waitForTimeout(), which could very well introduce flakyness.
By waiting on the specific element it also allows the implementation of handleConnectionDialog() method to be refactored, as pointed out below.
if (isRootful !== (await this.isEnabled(this.rootPriviledgesCheckbox))) { | ||
await this.switchCheckbox(this.rootPriviledgesCheckbox); | ||
} | ||
|
||
if (enableUserNet !== (await this.isEnabled(this.userModeNetworkingCheckbox))) { | ||
await this.switchCheckbox(this.userModeNetworkingCheckbox); | ||
} | ||
|
||
if (startNow !== (await this.isEnabled(this.startNowCheckbox))) { | ||
await this.switchCheckbox(this.startNowCheckbox); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These can be refactor in order for the if statements to not be required, there should be some method named ensureCheckboxState()
that accepts the checkbox locator and the desired state of the checkbox which checks the initial state and switches the state in case it does not match the desired state.
@@ -0,0 +1,134 @@ | |||
/********************************************************************** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
File should be added to index.ts file to be exported.
|
||
test.afterAll(async () => { | ||
await deletePodmanMachine(page, MACHINE_VISIBLE_NAME); | ||
await pdRunner.close(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the close() method call should always be in a finally block, in order to ensure that it's executed even if some exception is thrown in the deletePodmanMachine() method.
const connectionStatusLabel = await machineBox.resourceElementConnectionStatus.textContent(); | ||
playExpect(connectionStatusLabel === 'RUNNING').toBeTruthy(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const connectionStatusLabel = await machineBox.resourceElementConnectionStatus.textContent(); | |
playExpect(connectionStatusLabel === 'RUNNING').toBeTruthy(); | |
await playExpect(await machineBox.resourceElementConnectionStatus).toContain('RUNNING'); |
pdRunner = new PodmanDesktopRunner(); | ||
page = await pdRunner.start(); | ||
pdRunner.setVideoAndTraceName('podman-machine-user-mode'); | ||
process.env.KEEP_TRACES_ON_PASS = 'true'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we setting this env var here?
const connectionStatusLabel = await machineBox.resourceElementConnectionStatus.textContent(); | ||
playExpect(connectionStatusLabel === 'RUNNING').toBeTruthy(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const connectionStatusLabel = await machineBox.resourceElementConnectionStatus.textContent(); | |
playExpect(connectionStatusLabel === 'RUNNING').toBeTruthy(); | |
await playExpect(await machineBox.resourceElementConnectionStatus).toContain('RUNNING'); |
const connectionStatusLabel = await machineBox.resourceElementConnectionStatus.textContent(); | ||
playExpect(connectionStatusLabel === 'RUNNING').toBeTruthy(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const connectionStatusLabel = await machineBox.resourceElementConnectionStatus.textContent(); | |
playExpect(connectionStatusLabel === 'RUNNING').toBeTruthy(); | |
await playExpect(await machineBox.resourceElementConnectionStatus).toContain('RUNNING'); |
export function checkForFailedTest(result: TaskResult, runner: PodmanDesktopRunner): void { | ||
if (result.errors && result.errors.length > 0) runner.setTestPassed(false); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this method used for?
@@ -137,7 +137,7 @@ export async function deletePod(page: Page, name: string): Promise<void> { | |||
async () => { | |||
return !!(await pods.getPodRowByName(name)); | |||
}, | |||
{ timeout: 20000 }, | |||
{ timeout: 20_000 }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are all these timeout refactorings required, what is the point of them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments in the PR.
Signed-off-by: Tamara Babalova <tbabalov@redhat.com>
Signed-off-by: Tamara Babalova <tbabalov@redhat.com>
Signed-off-by: Tamara Babalova <tbabalov@redhat.com>
Signed-off-by: Tamara Babalova <tbabalov@redhat.com>
Signed-off-by: Tamara Babalova <tbabalov@redhat.com>
Signed-off-by: Tamara Babalova <tbabalov@redhat.com>
Signed-off-by: Tamara Babalova <tbabalov@redhat.com>
Signed-off-by: Tamara Babalova <tbabalov@redhat.com>
Signed-off-by: xbabalov <t.babalova.17@gmail.com>
Signed-off-by: xbabalov <t.babalova.17@gmail.com>
Signed-off-by: Daniel Villanueva <davillan@redhat.com>
Signed-off-by: Daniel Villanueva <davillan@redhat.com>
Signed-off-by: Daniel Villanueva <davillan@redhat.com>
Signed-off-by: Daniel Villanueva <davillan@redhat.com>
Signed-off-by: Daniel Villanueva <davillan@redhat.com>
Signed-off-by: Daniel Villanueva <davillan@redhat.com>
Signed-off-by: Daniel Villanueva <davillan@redhat.com>
Signed-off-by: Daniel Villanueva <davillan@redhat.com>
d5717a1
to
afd4492
Compare
What does this PR do?
This PR extends the E2E test suite by adding the test case of creating a rootfull/rootless Podman machine with user mode networking enabled
What issues does this PR fix or reference?
#4666
How to test this PR?
Run the e2e tests with yarn test:e2e