diff --git a/CHANGELOG.md b/CHANGELOG.md index dfb9f00..d6050f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ All notable changes to the Apify Java client are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.11.0] - 2026-10-26 + +### Added + +- `Build.getActorDefinition()` and the `ActorDefinition`, `ActorDefinitionMeta` and + `ActorDefinitionStorages` models for the build's `actorDefinition`, including the new `title`, + `description`, `output`, `meta`, `storages.datasets`, `storages.keyValueStore`, + `webServerSchema` and `webServerMcpPath` fields. + +### Fixed + +- An explicit JSON `null` for a raw-JSON (`JsonNode`) model field, such as `Task.getInput()`, is now + returned as Java `null` instead of a `NullNode`. + +### Changed + +- Updated to Apify OpenAPI specification `v2-2026-10-26T112451Z`. +- Documented that only runs with status `SUCCEEDED`, `FAILED`, `ABORTED` or `TIMED-OUT` can be + resurrected with `RunClient.resurrect`. + ## [0.10.0] - 2026-10-21 ### Added diff --git a/README.md b/README.md index c272636..b3b3f8a 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Maven (Maven Central is a default repository, so no extra configuration is neede com.apify apify-client - 0.10.0 + 0.11.0 ``` @@ -35,7 +35,7 @@ repositories { } dependencies { - implementation 'com.apify:apify-client:0.10.0' + implementation 'com.apify:apify-client:0.11.0' } ``` @@ -317,10 +317,10 @@ try { The public `com.apify.client.Version` class (`import com.apify.client.Version;`) exposes two constants: -- `Version.CLIENT_VERSION` — the semantic version of this client (`0.10.0`). +- `Version.CLIENT_VERSION` — the semantic version of this client (`0.11.0`). - `Version.API_SPEC_VERSION` — the version of the [Apify OpenAPI specification](https://docs.apify.com/api/openapi.json) (its `info.version` field) that this client's endpoints, parameters and models were last generated - and checked against (`v2-2026-10-20T121847Z`). It is a snapshot, not a live compatibility + and checked against (`v2-2026-10-26T112451Z`). It is a snapshot, not a live compatibility guarantee: the client keeps working against newer, backward-compatible spec revisions, but a feature added to the API after this snapshot has no corresponding method here yet. diff --git a/docs/README.md b/docs/README.md index 04ad78f..92fa938 100644 --- a/docs/README.md +++ b/docs/README.md @@ -41,7 +41,7 @@ option types, so import each resource you use from its own package: | `com.apify.client` (root) | `ApifyClient`, `ApifyClientBuilder`, `Version`, `PaginationList`, `ListOptions`, `StorageListOptions`, `ApifyResource` | | `com.apify.client.http` | `ApifyClientException`, `ApifyApiException`, `ApifyTransportException`, `HttpTransport`, `DefaultHttpTransport`, `HttpTimeoutException` | | `com.apify.client.actor` | `Actor`, `ActorClient`, `ActorCollectionClient`, `ActorListOptions`, `ActorStartOptions`, `ActorCallOptions`, `ActorBuildOptions`, `ActorStandby`, `ActorVersion`, `SourceCodeFile`, `ActorVersionClient`, `ActorVersionCollectionClient`, `ActorEnvVar`, `ActorEnvVarClient`, `ActorEnvVarCollectionClient`, `ValidateInputOptions`, `ActorStats`, `ActorDefaultRunOptions` | -| `com.apify.client.build` | `Build`, `BuildClient`, `BuildCollectionClient`, `BuildActVersion`, `BuildMeta`, `BuildStats`, `BuildOptions`, `BuildUsage` | +| `com.apify.client.build` | `Build`, `BuildClient`, `BuildCollectionClient`, `BuildActVersion`, `ActorDefinition`, `ActorDefinitionMeta`, `ActorDefinitionStorages`, `BuildMeta`, `BuildStats`, `BuildOptions`, `BuildUsage` | | `com.apify.client.run` | `ActorRun`, `ActorRunStats`, `ActorRunOptions`, `ActorRunMeta`, `ActorRunUsage`, `RunClient`, `RunCollectionClient`, `RunListOptions`, `LastRunOptions`, `MetamorphOptions`, `RunChargeOptions`, `RunResurrectOptions`, `SetStatusMessageOptions` | | `com.apify.client.dataset` | `Dataset`, `DatasetClient`, `DatasetCollectionClient`, `DatasetListItemsOptions`, `DatasetDownloadOptions`, `DownloadItemsFormat` | | `com.apify.client.keyvalue` | `KeyValueStore`, `KeyValueStoreClient`, `KeyValueStoreCollectionClient`, `KeyValueStoreRecord`, `KeyValueStoreKeysPage`, `KeyValueStoreKey`, `GetRecordOptions`, `SetRecordOptions`, `ListKeysOptions` | diff --git a/docs/builds.md b/docs/builds.md index b1f5d8c..7255e2e 100644 --- a/docs/builds.md +++ b/docs/builds.md @@ -25,7 +25,14 @@ builds) and a single build with `client.build(id)`. `Build` fields: `getId()`, `getActId()`, `getUserId()`, `getStatus()`, `getStartedAt()`, `getFinishedAt()`, `getBuildNumber()`, `getActVersion()` (`BuildActVersion` — `getSourceType()`, `getBuildTag()` (nullable), `getVersionNumber()`, `getGitRepoUrl()`, `getSourceFiles()` (`List` — `getName()`, -`getFormat()`, `getContent()`)), `getImageDigest()` (`String`, nullable — the built Docker +`getFormat()`, `getContent()`)), `getActorDefinition()` (`ActorDefinition`, nullable — the Actor's `.actor/actor.json` at build time: +`getActorSpecification()`, `getName()`, `getTitle()`, `getDescription()`, `getVersion()`, `getBuildTag()`, +`getMeta()` (`ActorDefinitionMeta` — `getTemplateId()`, `getGeneratedBy()`), `getEnvironmentVariables()`, +`getDockerfile()`, `getDockerContextDir()`, `getReadme()`, `getInput()`/`getOutput()` (`JsonNode` schemas), +`getChangelog()`, `getStorages()` (`ActorDefinitionStorages` — `getDataset()`, `getDatasets()`, +`getKeyValueStore()`), `getDefaultMemoryMbytes()` (`JsonNode`, an integer or a dynamic memory +expression), `getMinMemoryMbytes()`, `getMaxMemoryMbytes()`, `getUsesStandbyMode()`, `getWebServerSchema()`, +`getWebServerMcpPath()`), `getImageDigest()` (`String`, nullable — the built Docker image manifest's digest, without the `sha256:` prefix; compare two builds' digests to tell whether their image contents differ), `getMeta()` (`BuildMeta` — `getOrigin()`, `getClientIp()`, `getUserAgent()`), `getStats()` (`BuildStats` — `getDurationMillis()`/`getRunTimeSecs()` as `Long`, @@ -34,7 +41,7 @@ their image contents differ), `getMeta()` (`BuildMeta` — `getOrigin()`, `getCl `getUsage()` / `getUsageUsd()` (`BuildUsage` — `getActorComputeUnits()` as `Double`, the latter as its USD cost), `getUsageTotalUsd()` (`Double`), plus `isTerminal()` and `getExtra()`. The status is one of `READY`, `RUNNING`, `SUCCEEDED`, `FAILED`, `TIMING-OUT`, `TIMED-OUT`, `ABORTING`, `ABORTED`. -Every nested model above (`BuildActVersion`, `BuildMeta`, `BuildStats`, `BuildOptions`, `BuildUsage`) also has its own +Every nested model above (`BuildActVersion`, `ActorDefinition`, `ActorDefinitionMeta`, `ActorDefinitionStorages`, `BuildMeta`, `BuildStats`, `BuildOptions`, `BuildUsage`) also has its own `getExtra()`, so a field not yet listed here is still reachable rather than dropped. ```java diff --git a/docs/runs.md b/docs/runs.md index 2668b71..c19d478 100644 --- a/docs/runs.md +++ b/docs/runs.md @@ -35,7 +35,7 @@ PaginationList runs = client.runs().list( | `abort(Boolean gracefully)` | Abort the run (`null` = server default). Completes with `ActorRun`. | | `metamorph(String targetActorId, Object input, MetamorphOptions)` | Metamorph into another Actor. Completes with `ActorRun`. | | `reboot()` | Reboot the run. Completes with `ActorRun`. | -| `resurrect(RunResurrectOptions)` | Resurrect a finished run. Completes with `ActorRun`. | +| `resurrect(RunResurrectOptions)` | Resurrect a finished run (status `SUCCEEDED`, `FAILED`, `ABORTED` or `TIMED-OUT`). Completes with `ActorRun`. | | `charge(RunChargeOptions)` | Charge a pay-per-event run for a named event. Completes with no value (`CompletableFuture`). | | `waitForFinish(Long waitSecs)` | Poll until the run finishes (`null` waits indefinitely). Completes with `ActorRun`. | | `dataset()` / `keyValueStore()` / `requestQueue()` | Clients for the run's default storages. | diff --git a/pom.xml b/pom.xml index e189322..fbe46db 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.apify apify-client - 0.10.0 + 0.11.0 jar Apify Java Client diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml index cfafadb..39df467 100644 --- a/spotbugs-exclude.xml +++ b/spotbugs-exclude.xml @@ -19,6 +19,7 @@ 2. UWF_UNWRITTEN_FIELD / UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD on Jackson-populated DTOs/response shapes ({@code KeyValueStoreKey}, {@code DeletedRequestInfo}, {@code ActorRunMeta}, {@code TaskOptions}, {@code WebhookLastDispatch}, {@code ActorDefaultRunOptions}, {@code BuildActVersion}, + {@code ActorDefinitionMeta}, {@code ActorDefinitionStorages}, {@code BuildMeta}, {@code BuildOptions}, {@code BuildStats}, {@code PricingInfo}, {@code ProxyGroup}, {@code UserProxy}, {@code WebhookDispatchEventData}, {@code WebhookDispatchWebhookInfo}, the internal error-response mapping in {@code HttpClientCore}): their fields are written by the @@ -75,6 +76,8 @@ + + @@ -110,10 +113,19 @@ + + + + + + + + + diff --git a/src/main/java/com/apify/client/Version.java b/src/main/java/com/apify/client/Version.java index 95b44ba..638cb83 100644 --- a/src/main/java/com/apify/client/Version.java +++ b/src/main/java/com/apify/client/Version.java @@ -13,13 +13,13 @@ public final class Version { * The semantic version of this client library (see SemVer). * Changes to the public interface other than additive ones are considered breaking changes. */ - public static final String CLIENT_VERSION = "0.10.0"; + public static final String CLIENT_VERSION = "0.11.0"; /** * The version of the Apify OpenAPI specification this client was generated and verified against. * Corresponds to the {@code info.version} field of the Apify OpenAPI document. */ - public static final String API_SPEC_VERSION = "v2-2026-10-20T121847Z"; + public static final String API_SPEC_VERSION = "v2-2026-10-26T112451Z"; private Version() {} } diff --git a/src/main/java/com/apify/client/build/ActorDefinition.java b/src/main/java/com/apify/client/build/ActorDefinition.java new file mode 100644 index 0000000..b96ea02 --- /dev/null +++ b/src/main/java/com/apify/client/build/ActorDefinition.java @@ -0,0 +1,148 @@ +package com.apify.client.build; + +import com.apify.client.ApifyResource; +import java.util.Collections; +import java.util.Map; +import tools.jackson.databind.JsonNode; + +/** + * The definition of an Actor, as stored in its {@code .actor/actor.json}, from {@link + * Build#getActorDefinition()}. Every field is optional. + */ +public final class ActorDefinition extends ApifyResource { + private Integer actorSpecification; + private String name; + private String title; + private String description; + private String version; + private String buildTag; + private ActorDefinitionMeta meta; + private Map environmentVariables; + private String dockerfile; + private String dockerContextDir; + private String readme; + private JsonNode input; + private JsonNode output; + private String changelog; + private ActorDefinitionStorages storages; + private JsonNode defaultMemoryMbytes; + private Long minMemoryMbytes; + private Long maxMemoryMbytes; + private Boolean usesStandbyMode; + private JsonNode webServerSchema; + private String webServerMcpPath; + + /** The Actor specification version that this Actor follows; always {@code 1}. */ + public Integer getActorSpecification() { + return actorSpecification; + } + + /** The name of the Actor. */ + public String getName() { + return name; + } + + /** The human-readable display title of the Actor, shown in Apify Console and Apify Store. */ + public String getTitle() { + return title; + } + + /** The description of the Actor. */ + public String getDescription() { + return description; + } + + /** The version of the Actor, a dot-separated sequence of numbers (e.g. {@code "0.1"}). */ + public String getVersion() { + return version; + } + + /** The tag applied to a successful build of the Actor; {@code latest} when not specified. */ + public String getBuildTag() { + return buildTag; + } + + /** Additional information about the Actor. */ + public ActorDefinitionMeta getMeta() { + return meta; + } + + /** + * Environment variables used during local development and deployment; an empty map when none are + * defined. + */ + public Map getEnvironmentVariables() { + return environmentVariables == null + ? Map.of() + : Collections.unmodifiableMap(environmentVariables); + } + + /** The path to the Dockerfile used for building the Actor on the platform. */ + public String getDockerfile() { + return dockerfile; + } + + /** The path to the directory used as the Docker context when building the Actor. */ + public String getDockerContextDir() { + return dockerContextDir; + } + + /** The path to the README file for the Actor; {@code null} if there is none. */ + public String getReadme() { + return readme; + } + + /** The input schema object; {@code null} if the Actor has no input schema. */ + public JsonNode getInput() { + return input; + } + + /** The output schema object; {@code null} if the Actor has no output schema. */ + public JsonNode getOutput() { + return output; + } + + /** The path to the CHANGELOG file shown in the Actor's information tab; may be {@code null}. */ + public String getChangelog() { + return changelog; + } + + /** The schemas of the Actor's storages. */ + public ActorDefinitionStorages getStorages() { + return storages; + } + + /** + * The default memory in megabytes used when the Actor is started: either a JSON integer or a + * string with a dynamic memory expression (e.g. {@code "get(input, 'startUrls.length', 1) * + * 1024"}). + */ + public JsonNode getDefaultMemoryMbytes() { + return defaultMemoryMbytes; + } + + /** The minimum memory in megabytes required by the Actor. */ + public Long getMinMemoryMbytes() { + return minMemoryMbytes; + } + + /** The maximum memory in megabytes required by the Actor. */ + public Long getMaxMemoryMbytes() { + return maxMemoryMbytes; + } + + /** Whether Standby mode is enabled for the Actor. */ + public Boolean getUsesStandbyMode() { + return usesStandbyMode; + } + + /** The OpenAPI v3 specification of the web server running in the Actor. */ + public JsonNode getWebServerSchema() { + return webServerSchema; + } + + /** The HTTP path where the Actor's web server exposes its MCP server (e.g. {@code "/mcp"}). */ + public String getWebServerMcpPath() { + return webServerMcpPath; + } +} diff --git a/src/main/java/com/apify/client/build/ActorDefinitionMeta.java b/src/main/java/com/apify/client/build/ActorDefinitionMeta.java new file mode 100644 index 0000000..49a8f12 --- /dev/null +++ b/src/main/java/com/apify/client/build/ActorDefinitionMeta.java @@ -0,0 +1,19 @@ +package com.apify.client.build; + +import com.apify.client.ApifyResource; + +/** Additional information about an Actor, from {@link ActorDefinition#getMeta()}. */ +public final class ActorDefinitionMeta extends ApifyResource { + private String templateId; + private String generatedBy; + + /** The ID of the template from which the Actor was created. */ + public String getTemplateId() { + return templateId; + } + + /** The tool or model that generated the Actor. */ + public String getGeneratedBy() { + return generatedBy; + } +} diff --git a/src/main/java/com/apify/client/build/ActorDefinitionStorages.java b/src/main/java/com/apify/client/build/ActorDefinitionStorages.java new file mode 100644 index 0000000..70656dc --- /dev/null +++ b/src/main/java/com/apify/client/build/ActorDefinitionStorages.java @@ -0,0 +1,34 @@ +package com.apify.client.build; + +import com.apify.client.ApifyResource; +import java.util.Collections; +import java.util.Map; +import tools.jackson.databind.JsonNode; + +/** The storage schemas of an Actor, from {@link ActorDefinition#getStorages()}. */ +public final class ActorDefinitionStorages extends ApifyResource { + private JsonNode dataset; + private Map datasets; + private JsonNode keyValueStore; + + /** + * The schema of the items in the Actor's dataset, as defined in the Actor's {@code + * .actor/actor.json}. + */ + public JsonNode getDataset() { + return dataset; + } + + /** + * Maps dataset aliases to the schemas of the Actor's datasets; an empty map when the Actor + * defines none. + */ + public Map getDatasets() { + return datasets == null ? Map.of() : Collections.unmodifiableMap(datasets); + } + + /** The schema of the Actor's default key-value store. */ + public JsonNode getKeyValueStore() { + return keyValueStore; + } +} diff --git a/src/main/java/com/apify/client/build/Build.java b/src/main/java/com/apify/client/build/Build.java index 7a01932..38b159f 100644 --- a/src/main/java/com/apify/client/build/Build.java +++ b/src/main/java/com/apify/client/build/Build.java @@ -15,6 +15,7 @@ public final class Build extends ApifyResource { private String buildNumber; private String imageDigest; private BuildActVersion actVersion; + private ActorDefinition actorDefinition; private BuildMeta meta; private BuildStats stats; private BuildOptions options; @@ -78,6 +79,14 @@ public BuildActVersion getActVersion() { return actVersion; } + /** + * The definition of the Actor this build was created from, as stored in its {@code + * .actor/actor.json}. {@code null} if the build has none. + */ + public ActorDefinition getActorDefinition() { + return actorDefinition; + } + /** Metadata about how the build was initiated. */ public BuildMeta getMeta() { return meta; diff --git a/src/main/java/com/apify/client/internal/Json.java b/src/main/java/com/apify/client/internal/Json.java index 2933554..f1d1096 100644 --- a/src/main/java/com/apify/client/internal/Json.java +++ b/src/main/java/com/apify/client/internal/Json.java @@ -2,10 +2,13 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; import tools.jackson.core.JacksonException; import tools.jackson.core.type.TypeReference; import tools.jackson.databind.DeserializationFeature; import tools.jackson.databind.JavaType; +import tools.jackson.databind.JsonNode; import tools.jackson.databind.ObjectMapper; import tools.jackson.databind.cfg.DateTimeFeature; import tools.jackson.databind.json.JsonMapper; @@ -37,6 +40,12 @@ public final class Json { // live API instead of every such field having to be widened to a boxed type. .configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false) .configure(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS, false) + // Jackson materializes an explicit JSON null for a JsonNode field as a NullNode, which + // is not a Java null. Models document nullable raw-JSON fields as returning null, so a + // null value is skipped and the field keeps its default of null. + .withConfigOverride( + JsonNode.class, + override -> override.setNullHandling(JsonSetter.Value.forValueNulls(Nulls.SKIP))) .changeDefaultPropertyInclusion( incl -> incl.withValueInclusion(JsonInclude.Include.NON_NULL)) // Bind directly to (private) fields so models need no setters — getters remain the diff --git a/src/main/java/com/apify/client/run/RunClient.java b/src/main/java/com/apify/client/run/RunClient.java index 3bf64a5..2236931 100644 --- a/src/main/java/com/apify/client/run/RunClient.java +++ b/src/main/java/com/apify/client/run/RunClient.java @@ -142,7 +142,10 @@ public CompletableFuture reboot() { return ctx.postWithBody("reboot", new QueryParams(), null, "", ActorRun.class); } - /** Resurrects a finished run, starting it again from the beginning. */ + /** + * Resurrects a finished run, starting it again from the beginning. Only runs with status {@code + * SUCCEEDED}, {@code FAILED}, {@code ABORTED} or {@code TIMED-OUT} can be resurrected. + */ public CompletableFuture resurrect(RunResurrectOptions options) { if (options == null) { throw new IllegalArgumentException("options is required and must not be null"); diff --git a/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java b/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java index 64278e2..bc56e16 100644 --- a/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java +++ b/src/test/java/com/apify/client/NestedDtoForwardCompatTest.java @@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import com.apify.client.actor.ActorStandby; +import com.apify.client.build.ActorDefinition; import com.apify.client.build.Build; import com.apify.client.build.BuildStats; import com.apify.client.internal.Json; @@ -14,6 +15,7 @@ import com.apify.client.run.ActorRunStats; import com.apify.client.schedule.ScheduleNotifications; import com.apify.client.store.PricingInfo; +import com.apify.client.task.Task; import com.apify.client.task.TaskStats; import com.apify.client.user.UserProfile; import com.apify.client.webhook.Webhook; @@ -104,6 +106,67 @@ void buildActVersionAcceptsNullBuildTag() { assertEquals("SOURCE_FILES", untagged.getActVersion().getSourceType()); } + @Test + void buildActorDefinitionModelsAllFieldsAndAcceptsNull() { + Build build = + parse( + "{\"id\":\"b1\",\"actorDefinition\":{\"actorSpecification\":1,\"name\":\"my-actor\"," + + "\"title\":\"My Actor\",\"description\":\"Does things\",\"version\":\"0.1\"," + + "\"buildTag\":\"latest\",\"meta\":{\"templateId\":\"js-start\"," + + "\"generatedBy\":\"Claude\"},\"environmentVariables\":{\"A\":\"b\"}," + + "\"dockerfile\":\"./Dockerfile\",\"dockerContextDir\":\"..\"," + + "\"readme\":\"./README.md\",\"input\":{\"type\":\"object\"}," + + "\"output\":{\"actorOutputSchemaVersion\":1},\"changelog\":null," + + "\"storages\":{\"dataset\":{\"views\":{}},\"datasets\":{\"extra\":{\"views\":{}}}," + + "\"keyValueStore\":{\"actorKeyValueStoreSchemaVersion\":1}}," + + "\"defaultMemoryMbytes\":\"get(input, 'n', 1) * 1024\",\"minMemoryMbytes\":128," + + "\"maxMemoryMbytes\":4096,\"usesStandbyMode\":true," + + "\"webServerSchema\":{\"openapi\":\"3.0.0\"},\"webServerMcpPath\":\"/mcp\"," + + "\"someFutureField\":1}}", + Build.class); + + ActorDefinition def = build.getActorDefinition(); + assertEquals(1, def.getActorSpecification().intValue()); + assertEquals("my-actor", def.getName()); + assertEquals("My Actor", def.getTitle()); + assertEquals("Does things", def.getDescription()); + assertEquals("0.1", def.getVersion()); + assertEquals("latest", def.getBuildTag()); + assertEquals("js-start", def.getMeta().getTemplateId()); + assertEquals("Claude", def.getMeta().getGeneratedBy()); + assertEquals("b", def.getEnvironmentVariables().get("A")); + assertEquals("./Dockerfile", def.getDockerfile()); + assertEquals("..", def.getDockerContextDir()); + assertEquals("./README.md", def.getReadme()); + assertEquals("object", def.getInput().get("type").asString()); + assertEquals(1, def.getOutput().get("actorOutputSchemaVersion").asInt()); + assertNull(def.getChangelog()); + assertTrue(def.getStorages().getDataset().has("views")); + assertTrue(def.getStorages().getDatasets().get("extra").has("views")); + assertEquals( + 1, def.getStorages().getKeyValueStore().get("actorKeyValueStoreSchemaVersion").asInt()); + assertEquals("get(input, 'n', 1) * 1024", def.getDefaultMemoryMbytes().asString()); + assertEquals(128L, def.getMinMemoryMbytes().longValue()); + assertEquals(4096L, def.getMaxMemoryMbytes().longValue()); + assertEquals(true, def.getUsesStandbyMode()); + assertEquals("3.0.0", def.getWebServerSchema().get("openapi").asString()); + assertEquals("/mcp", def.getWebServerMcpPath()); + assertEquals(1, def.getExtra().get("someFutureField")); + + ActorDefinition empty = + parse("{\"id\":\"b2\",\"actorDefinition\":{}}", Build.class).getActorDefinition(); + assertTrue(empty.getEnvironmentVariables().isEmpty()); + assertNull(empty.getStorages()); + ActorDefinition nulls = + parse("{\"id\":\"b5\",\"actorDefinition\":{\"input\":null,\"output\":null}}", Build.class) + .getActorDefinition(); + assertNull(nulls.getInput()); + assertNull(nulls.getOutput()); + assertNull(parse("{\"id\":\"t1\",\"input\":null}", Task.class).getInput()); + assertNull(parse("{\"id\":\"b3\",\"actorDefinition\":null}", Build.class).getActorDefinition()); + assertNull(parse("{\"id\":\"b4\"}", Build.class).getActorDefinition()); + } + @Test void webhookModelsAdHocFlagAndCondition() { Webhook adHoc = diff --git a/src/test/java/com/apify/client/integration/BuildIntegrationTest.java b/src/test/java/com/apify/client/integration/BuildIntegrationTest.java index 88502c9..fc41888 100644 --- a/src/test/java/com/apify/client/integration/BuildIntegrationTest.java +++ b/src/test/java/com/apify/client/integration/BuildIntegrationTest.java @@ -7,6 +7,7 @@ import com.apify.client.ListOptions; import com.apify.client.actor.Actor; import com.apify.client.actor.ActorBuildOptions; +import com.apify.client.build.ActorDefinition; import com.apify.client.build.Build; import com.apify.client.build.BuildClient; import org.junit.jupiter.api.Test; @@ -20,6 +21,16 @@ void listBuilds() { assertTrue(page.getTotal() >= 0); } + @Test + void storeActorBuildCarriesActorDefinition() { + ApifyClient client = requireClient(); + Build build = + client.actor("apify/hello-world").defaultBuild(60L).join().get().join().orElseThrow(); + ActorDefinition definition = build.getActorDefinition(); + assertNotNull(definition, "the default build of a store Actor carries its actorDefinition"); + assertNotNull(definition.getInput(), "hello-world declares an input schema"); + } + @Test void buildActorFlow() { ApifyClient client = requireClient();