Tests: browse's clones never see another test's OXY_TOKEN 19c71c828f86
private_repositories_and_push_tokens set OXY_TOKEN for the whole process around one clone, and create_push_and_browse, running beside it, now and then cloned with it: 'unknown token' (gate, 2026-10-16) and 'not unbound' (Flow run 330's test-postgres). Every clone in browse.rs, and that variable's setting, now hold one lock. Closes #247
- Author
- Andy McCall @andymccall <[email protected]>
- via
- agent
Claude Code <[email protected]> · delegate for changes, until 2026-11-13 19:00Z · key ea5f78160088
- When
- · 2026-10-17 01:20 UTC
- Signature
- ✔ signed by Claude Code
- Hash
19c71c828f86cc7dbcdd8d0c8d34d9f470b90a45d4bc384686498305b0f6b33e- Depends on
- d23464c0ac60
- Depended on by
- nothing yet
- In bookmarks
- api-unknown-fields cancel-landed-runs diffusion-pin-bookmark draft-ready main oh-comment-body-file proposal-list-fast
- In tags
- v0.6.0 v0.6.1 v0.7.0 v0.8.0 v0.9.0 v0.9.1 v0.9.11 v0.9.15 v0.9.16 v0.9.19 v0.9.2 v0.9.20 v0.9.21 v0.9.22 v0.9.23 v0.9.24 v0.9.3 v0.9.4 v0.9.5 v0.9.6 v0.9.7 v0.9.8 v0.9.9
- Edits
- 6 atoms, 0 tree operations, 1 file
Browse the tree at this change
modified crates/hub/tests/browse.rs +19 −6
| … | 34 unchanged lines |
||
| 35 | 35 | _dir: tempfile::TempDir, |
|
| 36 | 36 | } |
|
| 37 | 37 | ||
| 38 | + | /// Held by every clone here and while OXY_TOKEN is set: the variable is the |
|
| 39 | + | /// whole process's, and a clone in another test sent it (oxygenhub#247). |
|
| 40 | + | static ENV: std::sync::Mutex<()> = std::sync::Mutex::new(()); |
|
| 41 | + | ||
| 42 | + | fn clone(url: &str, dir: &Path) -> Result<Repo, oxy_core::repo::RepoError> { |
|
| 43 | + | let _env = ENV.lock().unwrap_or_else(|p| p.into_inner()); |
|
| 44 | + | Repo::clone(url, dir) |
|
| 45 | + | } |
|
| 46 | + | ||
| 38 | 47 | async fn hub(push_tokens: Vec<String>) -> Hub { |
|
| 39 | 48 | hermetic(); |
|
| 40 | 49 | let dir = tempfile::tempdir().unwrap(); |
|
| … | 27 unchanged lines |
||
| 68 | 77 | // The hosted repository is unbound until the first push, so it cannot |
|
| 69 | 78 | // be cloned yet: start locally and push, as moving an existing |
|
| 70 | 79 | // repository to the hub does. |
|
| 71 | - | assert!(Repo::clone(url, &work.join("early")).err().unwrap().to_string().contains("unbound")); |
|
| 80 | + | assert!(clone(url, &work.join("early")).err().unwrap().to_string().contains("unbound")); |
|
| 72 | 81 | let mut client = Repo::init(work).unwrap(); |
|
| 73 | 82 | // A signing identity, so changes and the tag travel signed. |
|
| 74 | 83 | client.create_identity("Test Author", "[email protected]", oxy_core::repo::IdentityScope::User).unwrap(); |
|
| … | 15 unchanged lines |
||
| 90 | 99 | let results = client.push_bookmark("origin", "feature", false).unwrap(); |
|
| 91 | 100 | assert!(results.iter().all(|r| r.ok), "{results:?}"); |
|
| 92 | 101 | // Bound now: a clone shares the id. |
|
| 93 | - | let clone = Repo::clone(url, &work.join("clone")).unwrap(); |
|
| 102 | + | let clone = clone(url, &work.join("clone")).unwrap(); |
|
| 94 | 103 | assert_eq!(clone.id().unwrap(), client.id().unwrap()); |
|
| 95 | 104 | (client, c1.to_hex(), c2.to_hex()) |
|
| 96 | 105 | } |
|
| … | 100 unchanged lines |
||
| 197 | 206 | // The private one is invisible on pages and to anonymous clients. |
|
| 198 | 207 | assert_eq!(get(&h.app, "/andy/priv").await.0, StatusCode::NOT_FOUND); |
|
| 199 | 208 | assert!(!page(&h.app, "/").await.contains("priv")); |
|
| 200 | - | assert!(Repo::clone(&format!("{}/andy/priv", h.base), &tempfile::tempdir().unwrap().path().join("x")).is_err()); |
|
| 209 | + | assert!(clone(&format!("{}/andy/priv", h.base), &tempfile::tempdir().unwrap().path().join("x")).is_err()); |
|
| 201 | 210 | // Anonymous push to the public one is refused; with the token it lands. |
|
| 202 | 211 | let work = tempfile::tempdir().unwrap(); |
|
| 203 | 212 | let mut client = Repo::init(work.path()).unwrap(); |
|
| … | 6 unchanged lines |
||
| 210 | 219 | assert!(client.push("origin", false).unwrap().iter().all(|r| r.ok)); |
|
| 211 | 220 | // With the token, the private repository can be cloned too. |
|
| 212 | 221 | let priv_dir = tempfile::tempdir().unwrap(); |
|
| 213 | - | std::env::set_var("OXY_TOKEN", "s3cret"); |
|
| 214 | - | let ok = Repo::clone(&format!("{}/andy/priv", h.base), &priv_dir.path().join("p")).is_ok(); |
|
| 215 | - | std::env::remove_var("OXY_TOKEN"); |
|
| 222 | + | let ok = { |
|
| 223 | + | let _env = ENV.lock().unwrap_or_else(|p| p.into_inner()); |
|
| 224 | + | std::env::set_var("OXY_TOKEN", "s3cret"); |
|
| 225 | + | let ok = Repo::clone(&format!("{}/andy/priv", h.base), &priv_dir.path().join("p")).is_ok(); |
|
| 226 | + | std::env::remove_var("OXY_TOKEN"); |
|
| 227 | + | ok |
|
| 228 | + | }; |
|
| 216 | 229 | assert!(ok, "a token reads a private repository until accounts exist"); |
|
| 217 | 230 | // The pushes log shows the accepted update; the front page shows activity. |
|
| 218 | 231 | tokio::time::sleep(std::time::Duration::from_millis(100)).await; |
|
| … | 3 unchanged lines |