Skip to main content

max / makenotwork

sando: test the promote happy path Every promote test asserted a refusal or a red outcome, so nothing pinned what a successful promote does. Cover it end to end on the existing rollback_fixture: gates green, deploy reaches the node, the current symlink flips, tier_state advances with previous_version set to the version we came off, a stale partial flag clears, and the deploy is recorded ok. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-22 18:08 UTC
Commit: fc70c26bdbb2c831d462af0cc62e952c06363e0b
Parent: cc67d78
1 file changed, +85 insertions, -0 deletions
@@ -1809,6 +1809,91 @@ mod tests {
1809 1809 }
1810 1810
1811 1811 #[tokio::test]
1812 + async fn promote_advances_the_tier_and_flips_the_symlink_when_gates_are_green() {
1813 + // The happy path. Every other promote test asserts a refusal or a red
1814 + // outcome, so nothing pinned what a *successful* promote actually does:
1815 + // deploy reaches the node, the `current` symlink flips, tier_state
1816 + // advances with previous_version = the version we came off, any stale
1817 + // partial flag clears, and the handler reports the nodes it touched.
1818 + use crate::topology::Gate;
1819 + let (mut state, _tmp) = rollback_fixture("1.0.0", "2.0.0").await;
1820 +
1821 + // Source tier `host` gates the promote on cargo_test. Satisfying it is
1822 + // the point of the test: the sibling case asserts an unsatisfied gate
1823 + // blocks, this one asserts a satisfied gate lets the promote through.
1824 + let mut topo = (*state.topo).clone();
1825 + topo.tiers[0].gates = vec![Gate::CargoTest];
1826 + state.topo = Arc::new(topo);
1827 + let pool = state.pool.clone();
1828 + let release_root = state.topo.tiers[1].nodes[0].release_root.clone();
1829 +
1830 + // 3.0.0 is staged on the build host and green on `host`.
1831 + tokio::fs::create_dir_all(
1832 + std::path::Path::new(&release_root)
1833 + .join("releases")
1834 + .join("3.0.0"),
1835 + )
1836 + .await
1837 + .unwrap();
1838 + sqlx::query("INSERT INTO versions (version, git_sha, built_at, artifact_path) VALUES ('3.0.0','sha',datetime('now'),'/tmp/staged/makenotwork')")
1839 + .execute(&pool).await.unwrap();
1840 + sqlx::query("UPDATE tier_state SET current_version = '3.0.0' WHERE tier = 'host'")
1841 + .execute(&pool)
1842 + .await
1843 + .unwrap();
1844 + insert_gate(&pool, "host", "3.0.0", "cargo_test", 1).await;
1845 +
1846 + // A stale flag from an earlier incident, which a clean rollout clears.
1847 + set_partial(&state, &tid("a"), "left over from a previous canary").await;
1848 +
1849 + let Json(body) = promote_inner(state, "a".into(), PromoteBody::default())
1850 + .await
1851 + .expect("gates are green and the node deploys, so the promote succeeds");
1852 +
1853 + assert_eq!(body["tier"], "a");
1854 + assert_eq!(body["version"], "3.0.0");
1855 + assert_eq!(
1856 + body["nodes_deployed"],
1857 + serde_json::json!(["a-local"]),
1858 + "the response names every node the promote reached",
1859 + );
1860 +
1861 + let (cur, prev) = tier_versions(&pool, "a").await;
1862 + assert_eq!(cur.as_deref(), Some("3.0.0"));
1863 + assert_eq!(
1864 + prev.as_deref(),
1865 + Some("2.0.0"),
1866 + "previous_version is the version we came off, so a rollback aims at it",
1867 + );
1868 +
1869 + // The node genuinely moved: the promote is not just bookkeeping.
1870 + let link = tokio::fs::read_link(std::path::Path::new(&release_root).join("current"))
1871 + .await
1872 + .unwrap();
1873 + assert_eq!(link.to_string_lossy(), "releases/3.0.0");
1874 +
1875 + let reason: Option<String> =
1876 + sqlx::query_scalar("SELECT partial_reason FROM tier_state WHERE tier = 'a'")
1877 + .fetch_one(&pool)
1878 + .await
1879 + .unwrap();
1880 + assert_eq!(
1881 + reason, None,
1882 + "a clean full rollout clears a stale partial flag",
1883 + );
1884 +
1885 + // The deploy is on the record as having succeeded, which is what the
1886 + // next promote's gate check and /state both read.
1887 + let (node, outcome): (String, String) =
1888 + sqlx::query_as("SELECT node, outcome FROM deploys WHERE version = '3.0.0'")
1889 + .fetch_one(&pool)
1890 + .await
1891 + .unwrap();
1892 + assert_eq!(node, "a-local");
1893 + assert_eq!(outcome, "ok");
1894 + }
1895 +
1896 + #[tokio::test]
1812 1897 async fn promote_fails_and_flags_the_tier_when_post_deploy_gates_are_red() {
1813 1898 // The deploy reached every node, so tier_state advances (a stale
1814 1899 // current_version would aim a later rollback at the wrong artifact), but