mod common;
use serde_json::json;
#[tokio::test(flavor = "multi_thread")]
async fn list_tasks() {
let client = require_client!();
let page = client
.tasks()
.list(Default::default())
.await
.expect("listing tasks should succeed");
assert!(page.total >= 0);
}
fn task_definition(name: &str) -> serde_json::Value {
json!({
"actId": "apify/hello-world",
"name": name,
"options": { "memoryMbytes": 256 },
"input": { "message": "hi" }
})
}
#[tokio::test(flavor = "multi_thread")]
async fn get_task() {
let client = require_client!();
let name = common::unique_name("task-get");
let task = client
.tasks()
.create(&task_definition(&name))
.await
.expect("create task");
let cleanup_client = client.clone();
let id = task.id.clone();
let _guard = common::Cleanup::new(move || async move {
let _ = cleanup_client.task(&id).delete().await;
});
let fetched = client
.task(&task.id)
.get()
.await
.expect("get task by id")
.expect("task should exist");
assert_eq!(fetched.id, task.id);
}
#[tokio::test(flavor = "multi_thread")]
async fn iterate_tasks() {
let client = require_client!();
let name = common::unique_name("task-iter");
let task = client
.tasks()
.create(&task_definition(&name))
.await
.expect("create task");
let cleanup_client = client.clone();
let id = task.id.clone();
let _guard = common::Cleanup::new(move || async move {
let _ = cleanup_client.task(&id).delete().await;
});
let target = task.id.clone();
assert!(
common::iter_contains_eventually(
|| {
client
.tasks()
.iterate(apify_client::ListOptions {
desc: Some(true),
..Default::default()
})
.with_chunk_size(5)
},
move |t| t.id == target,
)
.await,
"task iteration should yield the created task"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn task_publish_unpublish() {
let client = require_client!();
let name = common::unique_name("task-publish");
let task = client
.tasks()
.create(&task_definition(&name))
.await
.expect("create task");
let cleanup_client = client.clone();
let id = task.id.clone();
let _guard = common::Cleanup::new(move || async move {
let _ = cleanup_client.task(&id).delete().await;
});
let task_client = client.task(&task.id);
let unpublished = task_client
.unpublish()
.await
.expect("unpublish an already-unpublished task should be a no-op");
assert_eq!(unpublished.is_public, Some(false));
match task_client.publish().await {
Err(apify_client::ApifyClientError::Api(err)) => {
assert_eq!(err.status_code, 403);
assert_eq!(err.error_type.as_deref(), Some("insufficient-permissions"));
}
other => panic!(
"expected publish() on a task for an Actor we don't own to fail with \
`insufficient-permissions`, got {other:?}"
),
}
}
fn owned_actor_definition(name: &str) -> serde_json::Value {
json!({
"name": name,
"isPublic": false,
"versions": [{
"versionNumber": "0.0",
"sourceType": "SOURCE_FILES",
"buildTag": "latest",
"sourceFiles": [
{
"name": "Dockerfile",
"format": "TEXT",
"content": "FROM apify/actor-node:20\nCOPY . ./\nCMD node main.js"
},
{
"name": "main.js",
"format": "TEXT",
"content": "console.log('hello from rust client test');"
}
]
}]
})
}
#[tokio::test(flavor = "multi_thread")]
async fn task_public_config_update() {
let client = require_client!();
let actor_name = common::unique_actor_name("task-pubcfg-actor");
let actor = client
.actors()
.create(&owned_actor_definition(&actor_name))
.await
.expect("create owned actor");
let cleanup_actor_client = client.clone();
let actor_id = actor.id.clone();
let _actor_guard = common::Cleanup::new(move || async move {
let _ = cleanup_actor_client.actor(&actor_id).delete().await;
});
let build = client
.actor(&actor.id)
.build("0.0", Default::default())
.await
.expect("start build");
let finished = client
.build(&build.id)
.wait_for_finish(Some(300))
.await
.expect("wait for build");
assert_eq!(
finished.status.as_deref(),
Some("SUCCEEDED"),
"build must succeed for the task to be able to reference it"
);
let task_name = common::unique_name("task-pubcfg");
let task = client
.tasks()
.create(&json!({ "actId": actor.id, "name": task_name }))
.await
.expect("create task for owned actor");
let cleanup_task_client = client.clone();
let task_id = task.id.clone();
let _task_guard = common::Cleanup::new(move || async move {
let _ = cleanup_task_client.task(&task_id).delete().await;
});
let task_client = client.task(&task.id);
let configured = task_client
.update(&json!({
"publicConfig": {
"seoTitle": "Test task",
"seoDescription": "A test task.",
}
}))
.await
.expect("set publicConfig on an owned actor's task");
let public_config = configured
.public_config
.expect("publicConfig should be set after update");
assert_eq!(public_config.seo_title.as_deref(), Some("Test task"));
assert_eq!(
public_config.seo_description.as_deref(),
Some("A test task.")
);
assert_eq!(public_config.published_at, None);
assert_eq!(configured.is_public, Some(false));
let unpublished = task_client
.unpublish()
.await
.expect("unpublish an already-unpublished task should be a no-op");
assert_eq!(unpublished.is_public, Some(false));
assert_eq!(
unpublished
.public_config
.as_ref()
.and_then(|c| c.seo_title.as_deref()),
Some("Test task"),
"unpublish must not disturb the previously-configured publicConfig"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn task_crud_flow() {
let client = require_client!();
let name = common::unique_name("task");
let task = client
.tasks()
.create(&task_definition(&name))
.await
.expect("create task");
assert_eq!(task.name.as_deref(), Some(name.as_str()));
let cleanup_client = client.clone();
let cleanup_id = task.id.clone();
let _guard = common::Cleanup::new(move || async move {
let _ = cleanup_client.task(&cleanup_id).delete().await;
});
let task_client = client.task(&task.id);
assert!(task_client.get().await.expect("get task").is_some());
let new_input = json!({ "message": "updated" });
task_client
.update_input(&new_input)
.await
.expect("update input");
let input = task_client.get_input().await.expect("get input");
assert!(input.is_some());
let renamed = common::unique_name("task-renamed");
let updated = task_client
.update(&json!({ "name": renamed, "description": "Updated by task_crud_flow." }))
.await
.expect("update task");
assert_eq!(updated.name.as_deref(), Some(renamed.as_str()));
assert_eq!(
updated.description.as_deref(),
Some("Updated by task_crud_flow.")
);
let runs = task_client
.runs()
.list(Default::default(), Default::default())
.await
.expect("list task runs");
assert!(runs.total >= 0);
task_client.delete().await.expect("delete task");
assert!(task_client.get().await.expect("get after delete").is_none());
}