mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-06 08:01:35 +00:00
e2e runs on all databases
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
DATABASE_URL=postgres://postgres:changeme@db/windmill?sslmode=disable
|
||||
WM_IMAGE=ghcr.io/windmill-labs/windmill-ee:main
|
||||
|
||||
@@ -34,11 +34,14 @@ services:
|
||||
deploy:
|
||||
replicas: 1
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 8000:8000
|
||||
expose:
|
||||
- 8000
|
||||
- 2525
|
||||
environment:
|
||||
- DATABASE_URL=${DATABASE_URL}
|
||||
- LICENSE_KEY=${LICENSE_KEY}
|
||||
- MODE=server
|
||||
depends_on:
|
||||
db:
|
||||
@@ -65,6 +68,7 @@ services:
|
||||
# privileged: true
|
||||
environment:
|
||||
- DATABASE_URL=${DATABASE_URL}
|
||||
- LICENSE_KEY=${LICENSE_KEY}
|
||||
- MODE=worker
|
||||
- WORKER_GROUP=default
|
||||
# Uncomment to enable PID namespace isolation (requires privileged: true above)
|
||||
@@ -100,6 +104,7 @@ services:
|
||||
# privileged: true
|
||||
environment:
|
||||
- DATABASE_URL=${DATABASE_URL}
|
||||
- LICENSE_KEY=${LICENSE_KEY}
|
||||
- MODE=worker
|
||||
- WORKER_GROUP=native
|
||||
- NUM_WORKERS=8
|
||||
@@ -113,6 +118,25 @@ services:
|
||||
- worker_logs:/tmp/windmill/logs
|
||||
logging: *default-logging
|
||||
|
||||
caddy:
|
||||
image: ghcr.io/windmill-labs/caddy-l4:latest
|
||||
restart: unless-stopped
|
||||
# Configure the mounted Caddyfile and the exposed ports or use another reverse proxy if needed
|
||||
volumes:
|
||||
- ../Caddyfile:/etc/caddy/Caddyfile
|
||||
- caddy_data:/data
|
||||
# - ../certs:/certs # Provide custom certificate files like cert.pem and key.pem to enable HTTPS - See the corresponding section in the Caddyfile
|
||||
ports:
|
||||
# To change the exposed port, simply change 80:80 to <desired_port>:80. No other changes needed
|
||||
- 80:80
|
||||
- 25:25
|
||||
# - 443:443 # Uncomment to enable HTTPS handling by Caddy
|
||||
environment:
|
||||
- BASE_URL=":80"
|
||||
# - BASE_URL=":443" # uncomment and comment line above to enable HTTPS via custom certificate and key files
|
||||
# - BASE_URL=mydomain.com # Uncomment and comment line above to enable HTTPS handling by Caddy
|
||||
logging: *default-logging
|
||||
|
||||
# E2E Testing Services
|
||||
mysql_e2e:
|
||||
image: mysql:8.0
|
||||
@@ -227,6 +251,7 @@ volumes:
|
||||
db_data: null
|
||||
worker_dependency_cache: null
|
||||
worker_logs: null
|
||||
caddy_data: null
|
||||
mysql_data: null
|
||||
mssql_data: null
|
||||
oracle_data: null
|
||||
|
||||
@@ -4,8 +4,9 @@ import { expect, Locator, Page } from '@playwright/test'
|
||||
import { getDbFeatures } from '../src/lib/components/apps/components/display/dbtable/dbFeatures'
|
||||
import { ConfirmationModal, Toast } from './utils'
|
||||
import { DbInput, DbType } from '../src/lib/components/dbTypes'
|
||||
import { DB_TYPES } from '../src/lib/consts'
|
||||
|
||||
export async function runDbManagerSimpleCRUDTest(page: Page, db: _DbType) {
|
||||
export async function runDbManagerSimpleCRUDTest(page: Page, dbType: _DbType) {
|
||||
let dbManager = new DbManagerPage(page)
|
||||
await dbManager.expectToBeVisible()
|
||||
|
||||
@@ -14,7 +15,8 @@ export async function runDbManagerSimpleCRUDTest(page: Page, db: _DbType) {
|
||||
// Create table
|
||||
const tableEditor = await dbManager.openCreateTableDrawer()
|
||||
await tableEditor.setTableName(friendTableName)
|
||||
await tableEditor.addColumn('name', 'TEXT')
|
||||
await tableEditor.addColumn('name', getDbDatatype(dbType, 'TEXT'))
|
||||
await tableEditor.getColumn('id').delete() // remove default id column
|
||||
await tableEditor.createTable()
|
||||
|
||||
await Toast.expectSuccess(page, `${friendTableName} created`)
|
||||
@@ -60,14 +62,14 @@ export async function runDbManagerAlterTableTest(page: Page, dbType: _DbType) {
|
||||
let tableEditor = await dbManager.openCreateTableDrawer()
|
||||
await tableEditor.setTableName(friendTableName)
|
||||
let friendIdCol = await tableEditor.getColumn('id') // deafult id column
|
||||
await friendIdCol.setType('INT')
|
||||
await friendIdCol.setType(getDbDatatype(dbType, 'INT'))
|
||||
if (dbFeatures.primaryKeys) {
|
||||
friendIdCol.setPrimaryKey(true)
|
||||
} else {
|
||||
await expect(await friendIdCol.primaryKeyCheckbox()).toBeHidden()
|
||||
}
|
||||
await tableEditor.addColumn('name', 'TEXT')
|
||||
await tableEditor.addColumn('created_at', dbType === 'ms_sql_server' ? 'DATETIME2' : 'TIMESTAMP')
|
||||
await tableEditor.addColumn('name', getDbDatatype(dbType, 'TEXT'))
|
||||
await tableEditor.addColumn('created_at', getDbDatatype(dbType, 'TIMESTAMP'))
|
||||
await tableEditor.createTable()
|
||||
await Toast.expectSuccess(page, `${friendTableName} created`)
|
||||
await page.waitForTimeout(100)
|
||||
@@ -77,12 +79,12 @@ export async function runDbManagerAlterTableTest(page: Page, dbType: _DbType) {
|
||||
tableEditor = await dbManager.openCreateTableDrawer()
|
||||
await tableEditor.setTableName(messageTableName)
|
||||
let messageIdCol = await tableEditor.getColumn('id') // deafult id column
|
||||
await messageIdCol.setType('INT')
|
||||
await messageIdCol.setType(getDbDatatype(dbType, 'INT'))
|
||||
if (dbFeatures.primaryKeys) messageIdCol.setPrimaryKey(true)
|
||||
await tableEditor.addColumn('friend_id', 'INT')
|
||||
let contentColumn = await tableEditor.addColumn('content', 'TEXT')
|
||||
await tableEditor.addColumn('friend_id', getDbDatatype(dbType, 'INT'))
|
||||
let contentColumn = await tableEditor.addColumn('content', getDbDatatype(dbType, 'TEXT'))
|
||||
await contentColumn.setSettings({ nullable: true })
|
||||
await tableEditor.addColumn('created_at', dbType === 'ms_sql_server' ? 'DATETIME2' : 'TIMESTAMP')
|
||||
await tableEditor.addColumn('created_at', getDbDatatype(dbType, 'TIMESTAMP'))
|
||||
if (dbFeatures.foreignKeys) {
|
||||
await tableEditor.addForeignKey(friendTableName, 'friend_id', 'id', {
|
||||
onDelete: 'Cascade',
|
||||
@@ -119,7 +121,7 @@ export async function runDbManagerAlterTableTest(page: Page, dbType: _DbType) {
|
||||
await tableEditor.setTableName(postsTableName)
|
||||
await idCol.delete()
|
||||
await friendCol.setName('person_id')
|
||||
await friendCol.setType('BIGINT')
|
||||
await friendCol.setType(getDbDatatype(dbType, 'BIGINT'))
|
||||
await friendCol.setSettings({
|
||||
defaultValue: dbFeatures.defaultValues ? '123' : undefined,
|
||||
nullable: false
|
||||
@@ -141,11 +143,11 @@ export async function runDbManagerAlterTableTest(page: Page, dbType: _DbType) {
|
||||
tableEditor = new TableEditorDrawer(page)
|
||||
await idCol.checkNotExists()
|
||||
await friendCol.checkNameIs('person_id')
|
||||
await friendCol.checkTypeIs('BIGINT')
|
||||
await friendCol.checkTypeIs(getDbDatatype(dbType, 'BIGINT'))
|
||||
if (dbFeatures.defaultValues) {
|
||||
await friendCol.checkSettingsIs({ defaultValue: /123/ })
|
||||
}
|
||||
await createdAtCol.checkTypeIs('TIMESTAMP')
|
||||
await createdAtCol.checkTypeIs(getDbDatatype(dbType, 'TIMESTAMP'))
|
||||
await createdAtCol.checkNameIs('created_at')
|
||||
if (dbFeatures.primaryKeys) {
|
||||
await friendCol.checkPrimaryKeyIs(true)
|
||||
@@ -359,6 +361,7 @@ class Column {
|
||||
async delete() {
|
||||
const deleteBtn = (await this.row()).locator('button.delete-column-btn')
|
||||
await deleteBtn.click()
|
||||
await this.page.waitForTimeout(50)
|
||||
}
|
||||
|
||||
async setPrimaryKey(isPrimaryKey: boolean) {
|
||||
@@ -490,3 +493,10 @@ function getDbInput(dbType: _DbType): DbInput {
|
||||
return { type: 'database', resourceType: dbType, resourcePath: '' }
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure exact casing of datatype as per DB_TYPES
|
||||
function getDbDatatype(dbType: _DbType, datatype: string): string {
|
||||
if (dbType === 'ms_sql_server' && datatype.toLowerCase() === 'timestamp') datatype = 'datetime2'
|
||||
const allDataTypes = DB_TYPES[dbType == 'ducklake' ? 'duckdb' : dbType] || []
|
||||
return allDataTypes.find((dt) => dt.toLowerCase() === datatype.toLowerCase()) || datatype
|
||||
}
|
||||
|
||||
@@ -47,6 +47,16 @@ async function globalSetup(config: FullConfig) {
|
||||
await page.waitForURL('**/')
|
||||
await page.locator('text=Home').first().waitFor({ state: 'visible' })
|
||||
|
||||
const hubSyncBtn = page.locator('text=u/admin/hub_sync')
|
||||
await hubSyncBtn.waitFor({ state: 'visible' })
|
||||
await hubSyncBtn.click()
|
||||
|
||||
const runBtn = page.locator('#run-form-run-button')
|
||||
await runBtn.waitFor({ state: 'visible' })
|
||||
await runBtn.click()
|
||||
await page.waitForURL(/\/run\/.+/)
|
||||
await page.locator('text=Success').waitFor({ timeout: 30000, state: 'visible' })
|
||||
|
||||
// Save the authenticated state
|
||||
await context.storageState({ path: './e2e/auth.json' })
|
||||
await browser.close()
|
||||
|
||||
@@ -14,15 +14,15 @@ test.describe('DB Manager', () => {
|
||||
|
||||
const resourceByDbType = {
|
||||
postgresql: {
|
||||
host: 'localhost',
|
||||
host: 'postgres_e2e',
|
||||
port: 5432,
|
||||
dbname: 'testing',
|
||||
user: 'postgres',
|
||||
password: 'changeme',
|
||||
dbname: 'test_db',
|
||||
user: 'test_user',
|
||||
password: 'postgres_password',
|
||||
sslmode: 'disable'
|
||||
},
|
||||
mysql: {
|
||||
host: 'localhost',
|
||||
host: 'mysql_e2e',
|
||||
port: 3306,
|
||||
user: 'test_user',
|
||||
database: 'test_db',
|
||||
@@ -32,10 +32,10 @@ const resourceByDbType = {
|
||||
oracle: {
|
||||
user: 'test_user',
|
||||
password: 'test_password',
|
||||
database: 'localhost:1521/test_db'
|
||||
database: 'oracle_e2e:1521/test_db'
|
||||
},
|
||||
ms_sql_server: {
|
||||
host: 'localhost',
|
||||
host: 'mssql_e2e',
|
||||
user: 'sa',
|
||||
password: 'MsSql_Pass123!',
|
||||
port: 1433,
|
||||
@@ -79,8 +79,6 @@ async function setupNewResource(
|
||||
const jsonEditor = page.locator('.simple-editor .view-lines')
|
||||
await expect(jsonEditor).toBeVisible()
|
||||
await jsonEditor.click({ clickCount: 4 }) // Select all existing text
|
||||
// We do copy paste to avoid issues with monaco helping with autocomplete and messing up the test
|
||||
await page.context().grantPermissions(['clipboard-read', 'clipboard-write'])
|
||||
await page.evaluate((c) => navigator.clipboard.writeText(c), JSON.stringify(resourceObj))
|
||||
await page.keyboard.press('ControlOrMeta+V')
|
||||
|
||||
@@ -101,3 +99,4 @@ async function setupNewResourceAndOpenDbManager(page: Page, dbType: DbType) {
|
||||
const manageButton = resourceRow.locator('button:has-text("Manage")')
|
||||
await manageButton.click()
|
||||
}
|
||||
declare const process: any // avoid TS errors
|
||||
|
||||
@@ -283,6 +283,7 @@
|
||||
<div class="flex gap-2 items-start flex-wrap justify-between mt-2 md:mt-6 mb-6">
|
||||
<div class="flex-row-reverse flex-wrap flex w-full gap-4">
|
||||
<Button
|
||||
id="run-form-run-button"
|
||||
{loading}
|
||||
variant="accent"
|
||||
btnClasses="!px-6 !py-1 !h-8 inline-flex gap-2"
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
}
|
||||
|
||||
let {
|
||||
id = '',
|
||||
id,
|
||||
aiId = undefined,
|
||||
aiDescription = undefined,
|
||||
size = 'md',
|
||||
|
||||
Reference in New Issue
Block a user