mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-13 08:02:47 +00:00
test: pin fork version history order, bundle and app script hash
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5c1440f68b
commit
571d90ae1f
@@ -0,0 +1,138 @@
|
||||
use serde_json::json;
|
||||
use sha2::{Digest, Sha256};
|
||||
use sqlx::{Pool, Postgres, Row};
|
||||
|
||||
use windmill_test_utils::*;
|
||||
|
||||
/// The fork copies version history in bulk, so the rows it creates are only tied back to their
|
||||
/// source by the order and id mapping the statements build. Seeded out of id order (the newest
|
||||
/// version first) so an aggregate ordered by id rather than `created_at` shows up here.
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_fork_clones_version_history(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
sqlx::query(
|
||||
"INSERT INTO flow (workspace_id, path, summary, description, value, edited_by, schema,
|
||||
extra_perms, versions)
|
||||
VALUES ('test-workspace', 'u/test-user/f', '', '', '{\"modules\":[]}', 'test-user',
|
||||
'{}', '{}', '{}')",
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
sqlx::query(
|
||||
"WITH v AS (
|
||||
INSERT INTO flow_version (workspace_id, path, value, created_by, created_at)
|
||||
VALUES ('test-workspace', 'u/test-user/f', '{\"n\":2}', 'test-user', now()),
|
||||
('test-workspace', 'u/test-user/f', '{\"n\":1}', 'test-user', now() - interval '1 hour')
|
||||
RETURNING id, created_at
|
||||
)
|
||||
UPDATE flow SET versions = (SELECT array_agg(id ORDER BY created_at) FROM v)
|
||||
WHERE workspace_id = 'test-workspace' AND path = 'u/test-user/f'",
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
let app_id: i64 = sqlx::query_scalar(
|
||||
"INSERT INTO app (workspace_id, path, summary, policy, versions)
|
||||
VALUES ('test-workspace', 'u/test-user/a', '', '{}', '{}') RETURNING id",
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
let (latest, older): (i64, i64) = {
|
||||
let ids: Vec<i64> = sqlx::query_scalar(
|
||||
"INSERT INTO app_version (app_id, value, created_by, created_at, raw_app)
|
||||
VALUES ($1, '{\"n\":2}', 'test-user', now(), true),
|
||||
($1, '{\"n\":1}', 'test-user', now() - interval '1 hour', true)
|
||||
RETURNING id",
|
||||
)
|
||||
.bind(app_id)
|
||||
.fetch_all(&db)
|
||||
.await?;
|
||||
(ids[0], ids[1])
|
||||
};
|
||||
sqlx::query("UPDATE app SET versions = ARRAY[$2, $3] WHERE id = $1")
|
||||
.bind(app_id)
|
||||
.bind(older)
|
||||
.bind(latest)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
sqlx::query(
|
||||
"INSERT INTO app_bundles (app_version_id, w_id, file_type, data)
|
||||
VALUES ($1, 'test-workspace', 'js', 'latest'), ($2, 'test-workspace', 'js', 'older')",
|
||||
)
|
||||
.bind(latest)
|
||||
.bind(older)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
let code_sha256 = format!("{:x}", Sha256::digest(b"code"));
|
||||
sqlx::query(
|
||||
"INSERT INTO app_script (app, hash, lock, code, code_sha256)
|
||||
VALUES ($1, 'source-hash', 'the lock', 'code', $2)",
|
||||
)
|
||||
.bind(app_id)
|
||||
.bind(&code_sha256)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
let resp = reqwest::Client::new()
|
||||
.post(format!(
|
||||
"http://localhost:{}/api/w/test-workspace/workspaces/create_fork",
|
||||
server.addr.port()
|
||||
))
|
||||
.header("Authorization", "Bearer SECRET_TOKEN")
|
||||
.json(&json!({ "id": "wm-fork-versions", "name": "Fork" }))
|
||||
.send()
|
||||
.await?;
|
||||
assert!(
|
||||
resp.status().is_success(),
|
||||
"creating the fork: {}",
|
||||
resp.text().await?
|
||||
);
|
||||
|
||||
let flow_values: Vec<serde_json::Value> = sqlx::query_scalar(
|
||||
"SELECT fv.value FROM flow f, unnest(f.versions) WITH ORDINALITY u(id, ord)
|
||||
JOIN flow_version fv ON fv.id = u.id AND fv.workspace_id = 'wm-fork-versions'
|
||||
WHERE f.workspace_id = 'wm-fork-versions' AND f.path = 'u/test-user/f' ORDER BY u.ord",
|
||||
)
|
||||
.fetch_all(&db)
|
||||
.await?;
|
||||
assert_eq!(flow_values, vec![json!({"n": 1}), json!({"n": 2})]);
|
||||
|
||||
let fork_app = sqlx::query(
|
||||
"SELECT id, versions FROM app WHERE workspace_id = 'wm-fork-versions' AND path = 'u/test-user/a'",
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
let fork_app_id: i64 = fork_app.get("id");
|
||||
let fork_versions: Vec<i64> = fork_app.get("versions");
|
||||
let app_values: Vec<String> = sqlx::query_scalar(
|
||||
"SELECT av.value::text FROM unnest($1::bigint[]) WITH ORDINALITY u(id, ord)
|
||||
JOIN app_version av ON av.id = u.id AND av.app_id = $2 ORDER BY u.ord",
|
||||
)
|
||||
.bind(&fork_versions)
|
||||
.bind(fork_app_id)
|
||||
.fetch_all(&db)
|
||||
.await?;
|
||||
assert_eq!(app_values, vec![r#"{"n":1}"#, r#"{"n":2}"#]);
|
||||
|
||||
// Only the current version's bundle is reachable, so only it is carried over.
|
||||
let bundles: Vec<(i64, Vec<u8>)> = sqlx::query_as(
|
||||
"SELECT app_version_id, data FROM app_bundles WHERE w_id = 'wm-fork-versions'",
|
||||
)
|
||||
.fetch_all(&db)
|
||||
.await?;
|
||||
assert_eq!(bundles, vec![(fork_versions[1], b"latest".to_vec())]);
|
||||
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(fork_app_id.to_be_bytes());
|
||||
hasher.update(hex::decode(&code_sha256)?);
|
||||
hasher.update(b"the lock");
|
||||
let hash: String = sqlx::query_scalar("SELECT hash FROM app_script WHERE app = $1")
|
||||
.bind(fork_app_id)
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
assert_eq!(hash, hex::encode(hasher.finalize()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user