Initial public release of Warp.
Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use chrono::Utc;
|
||||
use tempfile::tempdir;
|
||||
use warp_cli::artifact::UploadArtifactArgs;
|
||||
|
||||
use super::*;
|
||||
use crate::ai::agent::api::ServerConversationToken;
|
||||
use crate::ai::agent::conversation::{AIAgentHarness, ServerAIConversationMetadata};
|
||||
use crate::cloud_object::{Revision, ServerMetadata, ServerPermissions};
|
||||
use crate::persistence::model::ConversationUsageMetadata;
|
||||
use crate::server::ids::ServerId;
|
||||
|
||||
fn create_mock_server_metadata() -> ServerMetadata {
|
||||
ServerMetadata {
|
||||
uid: ServerId::default(),
|
||||
revision: Revision::now(),
|
||||
metadata_last_updated_ts: Utc::now().into(),
|
||||
trashed_ts: None,
|
||||
folder_id: None,
|
||||
is_welcome_object: false,
|
||||
creator_uid: None,
|
||||
last_editor_uid: None,
|
||||
current_editor_uid: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_conversation_metadata(
|
||||
conversation_id: &str,
|
||||
ambient_task_id: Option<&str>,
|
||||
) -> ServerAIConversationMetadata {
|
||||
ServerAIConversationMetadata {
|
||||
title: "Artifact upload".to_string(),
|
||||
working_directory: None,
|
||||
harness: AIAgentHarness::Oz,
|
||||
usage: ConversationUsageMetadata {
|
||||
was_summarized: false,
|
||||
context_window_usage: 0.0,
|
||||
credits_spent: 0.0,
|
||||
credits_spent_for_last_block: None,
|
||||
token_usage: vec![],
|
||||
tool_usage_metadata: Default::default(),
|
||||
},
|
||||
metadata: create_mock_server_metadata(),
|
||||
permissions: ServerPermissions::mock_personal(),
|
||||
ambient_agent_task_id: ambient_task_id.map(|task_id| task_id.parse().unwrap()),
|
||||
server_conversation_token: ServerConversationToken::new(conversation_id.to_string()),
|
||||
artifacts: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_artifact_filepath_preserves_shape_and_normalizes_separators() {
|
||||
let path = PathBuf::from(r"outputs\reports/final.txt");
|
||||
assert_eq!(
|
||||
normalize_artifact_filepath(&path),
|
||||
"outputs/reports/final.txt"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_graphql_size_bytes_for_upload_returns_none_for_overflow() {
|
||||
let path = PathBuf::from("outputs/large-artifact.bin");
|
||||
|
||||
assert_eq!(
|
||||
checked_graphql_size_bytes_for_upload(&path, i32::MAX as u64),
|
||||
Some(i32::MAX)
|
||||
);
|
||||
assert_eq!(
|
||||
checked_graphql_size_bytes_for_upload(&path, i32::MAX as u64 + 1),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_size_and_prefix_for_path_returns_truncated_prefix() {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let path = tempdir.path().join("artifact.bin");
|
||||
fs::write(&path, b"0123456789").unwrap();
|
||||
|
||||
assert_eq!(
|
||||
file_size_and_prefix_for_path(&path, 4).unwrap(),
|
||||
(10, b"0123".to_vec())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_size_and_prefix_for_path_returns_full_contents_when_prefix_exceeds_file() {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let path = tempdir.path().join("artifact.bin");
|
||||
fs::write(&path, b"0123456789").unwrap();
|
||||
|
||||
assert_eq!(
|
||||
file_size_and_prefix_for_path(&path, 32).unwrap(),
|
||||
(10, b"0123456789".to_vec())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_conversation_metadata_returns_the_only_metadata_record() {
|
||||
let metadata = single_conversation_metadata(
|
||||
"conversation-123",
|
||||
vec![create_conversation_metadata(
|
||||
"conversation-123",
|
||||
Some("550e8400-e29b-41d4-a716-446655440000"),
|
||||
)],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let task_id = ambient_task_id_from_conversation_metadata("conversation-123", metadata).unwrap();
|
||||
assert_eq!(
|
||||
task_id,
|
||||
"550e8400-e29b-41d4-a716-446655440000".parse().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_conversation_metadata_errors_when_no_metadata_is_returned() {
|
||||
let err = single_conversation_metadata("conversation-123", Vec::new()).unwrap_err();
|
||||
|
||||
assert!(err.to_string().contains("Conversation not found"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ambient_task_id_from_conversation_metadata_requires_cloud_task_metadata() {
|
||||
let err = ambient_task_id_from_conversation_metadata(
|
||||
"conversation-123",
|
||||
create_conversation_metadata("conversation-123", None),
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
assert!(err
|
||||
.to_string()
|
||||
.contains("Conversation 'conversation-123' is not backed by a cloud agent task"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_run_id_wins_over_env_fallback() {
|
||||
let resolved = resolve_upload_association_from_sources(
|
||||
Some("550e8400-e29b-41d4-a716-446655440000".parse().unwrap()),
|
||||
None,
|
||||
None,
|
||||
Some("11111111-1111-1111-1111-111111111111".to_string()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
resolved,
|
||||
ResolvedUploadAssociation {
|
||||
conversation_id: None,
|
||||
run_id: Some("550e8400-e29b-41d4-a716-446655440000".parse().unwrap()),
|
||||
ambient_task_id: "550e8400-e29b-41d4-a716-446655440000".parse().unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_explicit_run_id_errors_even_if_env_fallback_exists() {
|
||||
let err = FileArtifactUploadRequest::try_from(UploadArtifactArgs {
|
||||
path: PathBuf::from("outputs/report.txt"),
|
||||
run_id: Some("not-a-run-id".to_string()),
|
||||
conversation_id: None,
|
||||
description: None,
|
||||
})
|
||||
.unwrap_err();
|
||||
|
||||
assert!(err.to_string().contains("Invalid run ID 'not-a-run-id'"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid_conversation_resolution_ignores_env_fallback() {
|
||||
let resolved = resolve_upload_association_from_sources(
|
||||
None,
|
||||
Some(ServerConversationToken::new("conversation-123".to_string())),
|
||||
Some(Ok("550e8400-e29b-41d4-a716-446655440000".parse().unwrap())),
|
||||
Some("11111111-1111-1111-1111-111111111111".to_string()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
resolved,
|
||||
ResolvedUploadAssociation {
|
||||
conversation_id: Some(ServerConversationToken::new("conversation-123".to_string())),
|
||||
run_id: None,
|
||||
ambient_task_id: "550e8400-e29b-41d4-a716-446655440000".parse().unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn failed_conversation_resolution_falls_back_to_env_run_id() {
|
||||
let resolved = resolve_upload_association_from_sources(
|
||||
None,
|
||||
Some(ServerConversationToken::new("conversation-123".to_string())),
|
||||
Some(Err(anyhow!(
|
||||
"Conversation 'conversation-123' is not backed by a cloud agent task"
|
||||
))),
|
||||
Some("550e8400-e29b-41d4-a716-446655440000".to_string()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
resolved,
|
||||
ResolvedUploadAssociation {
|
||||
conversation_id: Some(ServerConversationToken::new("conversation-123".to_string())),
|
||||
run_id: None,
|
||||
ambient_task_id: "550e8400-e29b-41d4-a716-446655440000".parse().unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_args_fall_back_to_env_run_id_for_request_association() {
|
||||
let resolved = resolve_upload_association_from_sources(
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some("550e8400-e29b-41d4-a716-446655440000".to_string()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
resolved,
|
||||
ResolvedUploadAssociation {
|
||||
conversation_id: None,
|
||||
run_id: Some("550e8400-e29b-41d4-a716-446655440000".parse().unwrap()),
|
||||
ambient_task_id: "550e8400-e29b-41d4-a716-446655440000".parse().unwrap(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_args_and_missing_env_return_clear_error() {
|
||||
let err = resolve_upload_association_from_sources(None, None, None, None).unwrap_err();
|
||||
|
||||
assert!(err
|
||||
.to_string()
|
||||
.contains("no usable --run-id or --conversation-id was provided"));
|
||||
assert!(err.to_string().contains("OZ_RUN_ID"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_env_run_id_returns_clear_error() {
|
||||
let err =
|
||||
resolve_upload_association_from_sources(None, None, None, Some("not-a-run-id".to_string()))
|
||||
.unwrap_err();
|
||||
|
||||
assert!(err.to_string().contains("Invalid OZ_RUN_ID 'not-a-run-id'"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_env_run_id_reads_variable() {
|
||||
let previous = env::var_os(OZ_RUN_ID_ENV_VAR);
|
||||
env::set_var(OZ_RUN_ID_ENV_VAR, "550e8400-e29b-41d4-a716-446655440000");
|
||||
|
||||
let loaded = load_env_run_id().unwrap();
|
||||
|
||||
match previous {
|
||||
Some(value) => env::set_var(OZ_RUN_ID_ENV_VAR, value),
|
||||
None => env::remove_var(OZ_RUN_ID_ENV_VAR),
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
loaded.as_deref(),
|
||||
Some("550e8400-e29b-41d4-a716-446655440000")
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user