diff --git a/CHANGELOG.md b/CHANGELOG.md
index b98aa38..cbaa13a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,17 @@ All notable changes to the AxonFlow Java SDK will be 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).
+## [3.6.0] - 2026-02-22
+
+### Added
+
+- Media governance configuration methods: `getMediaGovernanceConfig()`, `updateMediaGovernanceConfig()`, `getMediaGovernanceStatus()`
+- Media governance types: `MediaGovernanceConfig`, `MediaGovernanceStatus`
+- Media policy category constants: `CATEGORY_MEDIA_SAFETY`, `CATEGORY_MEDIA_BIOMETRIC`, `CATEGORY_MEDIA_PII`, `CATEGORY_MEDIA_DOCUMENT`
+- `PolicyCategory` enum values: `MEDIA_SAFETY`, `MEDIA_BIOMETRIC`, `MEDIA_PII`, `MEDIA_DOCUMENT`
+
+---
+
## [3.5.0] - 2026-02-18
### Added
diff --git a/pom.xml b/pom.xml
index 19ecd38..39e41d0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.getaxonflow
axonflow-sdk
- 3.5.0
+ 3.6.0
jar
AxonFlow Java SDK
diff --git a/src/main/java/com/getaxonflow/sdk/AxonFlow.java b/src/main/java/com/getaxonflow/sdk/AxonFlow.java
index cf54b91..c494000 100644
--- a/src/main/java/com/getaxonflow/sdk/AxonFlow.java
+++ b/src/main/java/com/getaxonflow/sdk/AxonFlow.java
@@ -2122,6 +2122,95 @@ public void streamExecutionStatus(
}
}
+ // ========================================================================
+ // Media Governance Config
+ // ========================================================================
+
+ /**
+ * Gets the media governance configuration for the current tenant.
+ *
+ *
Returns per-tenant settings controlling whether media analysis is
+ * enabled and which analyzers are allowed.
+ *
+ * @return the media governance configuration
+ * @throws AxonFlowException if the request fails
+ */
+ public MediaGovernanceConfig getMediaGovernanceConfig() {
+ return retryExecutor.execute(() -> {
+ Request httpRequest = buildRequest("GET", "/api/v1/media-governance/config", null);
+ try (Response response = httpClient.newCall(httpRequest).execute()) {
+ return parseResponse(response, MediaGovernanceConfig.class);
+ }
+ }, "getMediaGovernanceConfig");
+ }
+
+ /**
+ * Asynchronously gets the media governance configuration for the current tenant.
+ *
+ * @return a future containing the media governance configuration
+ */
+ public CompletableFuture getMediaGovernanceConfigAsync() {
+ return CompletableFuture.supplyAsync(this::getMediaGovernanceConfig, asyncExecutor);
+ }
+
+ /**
+ * Updates the media governance configuration for the current tenant.
+ *
+ * Allows enabling/disabling media analysis and controlling which
+ * analyzers are permitted.
+ *
+ * @param request the update request
+ * @return the updated media governance configuration
+ * @throws AxonFlowException if the request fails
+ */
+ public MediaGovernanceConfig updateMediaGovernanceConfig(UpdateMediaGovernanceConfigRequest request) {
+ Objects.requireNonNull(request, "request cannot be null");
+
+ return retryExecutor.execute(() -> {
+ Request httpRequest = buildRequest("PUT", "/api/v1/media-governance/config", request);
+ try (Response response = httpClient.newCall(httpRequest).execute()) {
+ return parseResponse(response, MediaGovernanceConfig.class);
+ }
+ }, "updateMediaGovernanceConfig");
+ }
+
+ /**
+ * Asynchronously updates the media governance configuration for the current tenant.
+ *
+ * @param request the update request
+ * @return a future containing the updated media governance configuration
+ */
+ public CompletableFuture updateMediaGovernanceConfigAsync(UpdateMediaGovernanceConfigRequest request) {
+ return CompletableFuture.supplyAsync(() -> updateMediaGovernanceConfig(request), asyncExecutor);
+ }
+
+ /**
+ * Gets the platform-level media governance status.
+ *
+ * Returns whether media governance is available, default enablement,
+ * and the required license tier.
+ *
+ * @return the media governance status
+ * @throws AxonFlowException if the request fails
+ */
+ public MediaGovernanceStatus getMediaGovernanceStatus() {
+ return retryExecutor.execute(() -> {
+ Request httpRequest = buildRequest("GET", "/api/v1/media-governance/status", null);
+ try (Response response = httpClient.newCall(httpRequest).execute()) {
+ return parseResponse(response, MediaGovernanceStatus.class);
+ }
+ }, "getMediaGovernanceStatus");
+ }
+
+ /**
+ * Asynchronously gets the platform-level media governance status.
+ *
+ * @return a future containing the media governance status
+ */
+ public CompletableFuture getMediaGovernanceStatusAsync() {
+ return CompletableFuture.supplyAsync(this::getMediaGovernanceStatus, asyncExecutor);
+ }
+
// ========================================================================
// Configuration Access
// ========================================================================
diff --git a/src/main/java/com/getaxonflow/sdk/types/MediaGovernanceConfig.java b/src/main/java/com/getaxonflow/sdk/types/MediaGovernanceConfig.java
new file mode 100644
index 0000000..1d32ce4
--- /dev/null
+++ b/src/main/java/com/getaxonflow/sdk/types/MediaGovernanceConfig.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2025 AxonFlow
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.getaxonflow.sdk.types;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Per-tenant media governance configuration.
+ *
+ * Controls whether media analysis is enabled for a tenant and which
+ * analyzers are allowed. Returned by the media governance config API.
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class MediaGovernanceConfig {
+
+ @JsonProperty("tenant_id")
+ private String tenantId;
+
+ @JsonProperty("enabled")
+ private boolean enabled;
+
+ @JsonProperty("allowed_analyzers")
+ private List allowedAnalyzers;
+
+ @JsonProperty("updated_at")
+ private String updatedAt;
+
+ @JsonProperty("updated_by")
+ private String updatedBy;
+
+ public MediaGovernanceConfig() {}
+
+ public String getTenantId() { return tenantId; }
+ public void setTenantId(String tenantId) { this.tenantId = tenantId; }
+
+ public boolean isEnabled() { return enabled; }
+ public void setEnabled(boolean enabled) { this.enabled = enabled; }
+
+ public List getAllowedAnalyzers() { return allowedAnalyzers; }
+ public void setAllowedAnalyzers(List allowedAnalyzers) { this.allowedAnalyzers = allowedAnalyzers; }
+
+ public String getUpdatedAt() { return updatedAt; }
+ public void setUpdatedAt(String updatedAt) { this.updatedAt = updatedAt; }
+
+ public String getUpdatedBy() { return updatedBy; }
+ public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy; }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ MediaGovernanceConfig that = (MediaGovernanceConfig) o;
+ return enabled == that.enabled &&
+ Objects.equals(tenantId, that.tenantId) &&
+ Objects.equals(allowedAnalyzers, that.allowedAnalyzers) &&
+ Objects.equals(updatedAt, that.updatedAt) &&
+ Objects.equals(updatedBy, that.updatedBy);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(tenantId, enabled, allowedAnalyzers, updatedAt, updatedBy);
+ }
+
+ @Override
+ public String toString() {
+ return "MediaGovernanceConfig{" +
+ "tenantId='" + tenantId + '\'' +
+ ", enabled=" + enabled +
+ ", allowedAnalyzers=" + allowedAnalyzers +
+ ", updatedAt='" + updatedAt + '\'' +
+ ", updatedBy='" + updatedBy + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/com/getaxonflow/sdk/types/MediaGovernanceStatus.java b/src/main/java/com/getaxonflow/sdk/types/MediaGovernanceStatus.java
new file mode 100644
index 0000000..de227d9
--- /dev/null
+++ b/src/main/java/com/getaxonflow/sdk/types/MediaGovernanceStatus.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2025 AxonFlow
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.getaxonflow.sdk.types;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Objects;
+
+/**
+ * Platform-level media governance status.
+ *
+ * Indicates whether media governance is available, the default enablement
+ * state, and the license tier required.
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class MediaGovernanceStatus {
+
+ @JsonProperty("available")
+ private boolean available;
+
+ @JsonProperty("enabled_by_default")
+ private boolean enabledByDefault;
+
+ @JsonProperty("per_tenant_control")
+ private boolean perTenantControl;
+
+ @JsonProperty("tier")
+ private String tier;
+
+ public MediaGovernanceStatus() {}
+
+ public boolean isAvailable() { return available; }
+ public void setAvailable(boolean available) { this.available = available; }
+
+ public boolean isEnabledByDefault() { return enabledByDefault; }
+ public void setEnabledByDefault(boolean enabledByDefault) { this.enabledByDefault = enabledByDefault; }
+
+ public boolean isPerTenantControl() { return perTenantControl; }
+ public void setPerTenantControl(boolean perTenantControl) { this.perTenantControl = perTenantControl; }
+
+ public String getTier() { return tier; }
+ public void setTier(String tier) { this.tier = tier; }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ MediaGovernanceStatus that = (MediaGovernanceStatus) o;
+ return available == that.available &&
+ enabledByDefault == that.enabledByDefault &&
+ perTenantControl == that.perTenantControl &&
+ Objects.equals(tier, that.tier);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(available, enabledByDefault, perTenantControl, tier);
+ }
+
+ @Override
+ public String toString() {
+ return "MediaGovernanceStatus{" +
+ "available=" + available +
+ ", enabledByDefault=" + enabledByDefault +
+ ", perTenantControl=" + perTenantControl +
+ ", tier='" + tier + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/com/getaxonflow/sdk/types/UpdateMediaGovernanceConfigRequest.java b/src/main/java/com/getaxonflow/sdk/types/UpdateMediaGovernanceConfigRequest.java
new file mode 100644
index 0000000..78812b6
--- /dev/null
+++ b/src/main/java/com/getaxonflow/sdk/types/UpdateMediaGovernanceConfigRequest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2025 AxonFlow
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.getaxonflow.sdk.types;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Request to update per-tenant media governance configuration.
+ *
+ *
Fields set to {@code null} are omitted from the JSON payload,
+ * allowing partial updates.
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UpdateMediaGovernanceConfigRequest {
+
+ @JsonProperty("enabled")
+ private Boolean enabled;
+
+ @JsonProperty("allowed_analyzers")
+ private List allowedAnalyzers;
+
+ public UpdateMediaGovernanceConfigRequest() {}
+
+ public Boolean getEnabled() { return enabled; }
+ public void setEnabled(Boolean enabled) { this.enabled = enabled; }
+
+ public List getAllowedAnalyzers() { return allowedAnalyzers; }
+ public void setAllowedAnalyzers(List allowedAnalyzers) { this.allowedAnalyzers = allowedAnalyzers; }
+
+ public static Builder builder() { return new Builder(); }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UpdateMediaGovernanceConfigRequest that = (UpdateMediaGovernanceConfigRequest) o;
+ return Objects.equals(enabled, that.enabled) &&
+ Objects.equals(allowedAnalyzers, that.allowedAnalyzers);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(enabled, allowedAnalyzers);
+ }
+
+ @Override
+ public String toString() {
+ return "UpdateMediaGovernanceConfigRequest{" +
+ "enabled=" + enabled +
+ ", allowedAnalyzers=" + allowedAnalyzers +
+ '}';
+ }
+
+ public static final class Builder {
+ private Boolean enabled;
+ private List allowedAnalyzers;
+
+ private Builder() {}
+
+ public Builder enabled(Boolean enabled) { this.enabled = enabled; return this; }
+ public Builder allowedAnalyzers(List allowedAnalyzers) { this.allowedAnalyzers = allowedAnalyzers; return this; }
+
+ public UpdateMediaGovernanceConfigRequest build() {
+ UpdateMediaGovernanceConfigRequest request = new UpdateMediaGovernanceConfigRequest();
+ request.enabled = this.enabled;
+ request.allowedAnalyzers = this.allowedAnalyzers;
+ return request;
+ }
+ }
+}
diff --git a/src/main/java/com/getaxonflow/sdk/types/policies/PolicyTypes.java b/src/main/java/com/getaxonflow/sdk/types/policies/PolicyTypes.java
index 2bc66ee..05ccb9b 100644
--- a/src/main/java/com/getaxonflow/sdk/types/policies/PolicyTypes.java
+++ b/src/main/java/com/getaxonflow/sdk/types/policies/PolicyTypes.java
@@ -29,6 +29,22 @@ public final class PolicyTypes {
private PolicyTypes() {}
+ // ========================================================================
+ // Media Governance Policy Category Constants
+ // ========================================================================
+
+ /** Policy category for media safety (NSFW, violence). */
+ public static final String CATEGORY_MEDIA_SAFETY = "media-safety";
+
+ /** Policy category for media biometric detection (faces, fingerprints). */
+ public static final String CATEGORY_MEDIA_BIOMETRIC = "media-biometric";
+
+ /** Policy category for sensitive document detection. */
+ public static final String CATEGORY_MEDIA_DOCUMENT = "media-document";
+
+ /** Policy category for PII detected in media (OCR text extraction). */
+ public static final String CATEGORY_MEDIA_PII = "media-pii";
+
// ========================================================================
// Enums
// ========================================================================
@@ -56,6 +72,12 @@ public enum PolicyCategory {
// Sensitive data category
SENSITIVE_DATA("sensitive-data"),
+ // Media governance categories
+ MEDIA_SAFETY("media-safety"),
+ MEDIA_BIOMETRIC("media-biometric"),
+ MEDIA_PII("media-pii"),
+ MEDIA_DOCUMENT("media-document"),
+
// Dynamic policy categories
DYNAMIC_RISK("dynamic-risk"),
DYNAMIC_COMPLIANCE("dynamic-compliance"),
diff --git a/src/test/java/com/getaxonflow/sdk/MediaGovernanceTest.java b/src/test/java/com/getaxonflow/sdk/MediaGovernanceTest.java
new file mode 100644
index 0000000..55cfee3
--- /dev/null
+++ b/src/test/java/com/getaxonflow/sdk/MediaGovernanceTest.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2026 AxonFlow
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.getaxonflow.sdk;
+
+import com.getaxonflow.sdk.types.MediaGovernanceConfig;
+import com.getaxonflow.sdk.types.MediaGovernanceStatus;
+import com.getaxonflow.sdk.types.UpdateMediaGovernanceConfigRequest;
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
+import com.github.tomakehurst.wiremock.junit5.WireMockTest;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.*;
+import static org.assertj.core.api.Assertions.*;
+
+/**
+ * Tests for Media Governance Config API methods on the AxonFlow client.
+ */
+@WireMockTest
+@DisplayName("Media Governance API Methods")
+class MediaGovernanceTest {
+
+ private AxonFlow axonflow;
+
+ private static final String SAMPLE_CONFIG_JSON =
+ "{" +
+ "\"tenant_id\": \"tenant_001\"," +
+ "\"enabled\": true," +
+ "\"allowed_analyzers\": [\"nsfw\", \"biometric\", \"ocr\"]," +
+ "\"updated_at\": \"2026-02-18T10:00:00Z\"," +
+ "\"updated_by\": \"admin@example.com\"" +
+ "}";
+
+ private static final String SAMPLE_STATUS_JSON =
+ "{" +
+ "\"available\": true," +
+ "\"enabled_by_default\": false," +
+ "\"per_tenant_control\": true," +
+ "\"tier\": \"enterprise\"" +
+ "}";
+
+ @BeforeEach
+ void setUp(WireMockRuntimeInfo wmRuntimeInfo) {
+ axonflow = AxonFlow.create(AxonFlowConfig.builder()
+ .endpoint(wmRuntimeInfo.getHttpBaseUrl())
+ .endpoint(wmRuntimeInfo.getHttpBaseUrl())
+ .build());
+ }
+
+ // ========================================================================
+ // getMediaGovernanceConfig
+ // ========================================================================
+
+ @Nested
+ @DisplayName("getMediaGovernanceConfig")
+ class GetMediaGovernanceConfig {
+
+ @Test
+ @DisplayName("should return media governance config")
+ void shouldReturnConfig() {
+ stubFor(get(urlEqualTo("/api/v1/media-governance/config"))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/json")
+ .withBody(SAMPLE_CONFIG_JSON)));
+
+ MediaGovernanceConfig config = axonflow.getMediaGovernanceConfig();
+
+ assertThat(config.getTenantId()).isEqualTo("tenant_001");
+ assertThat(config.isEnabled()).isTrue();
+ assertThat(config.getAllowedAnalyzers()).containsExactly("nsfw", "biometric", "ocr");
+ assertThat(config.getUpdatedAt()).isEqualTo("2026-02-18T10:00:00Z");
+ assertThat(config.getUpdatedBy()).isEqualTo("admin@example.com");
+ }
+
+ @Test
+ @DisplayName("should return disabled config")
+ void shouldReturnDisabledConfig() {
+ stubFor(get(urlEqualTo("/api/v1/media-governance/config"))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/json")
+ .withBody("{\"tenant_id\": \"tenant_002\", \"enabled\": false, \"allowed_analyzers\": []}")));
+
+ MediaGovernanceConfig config = axonflow.getMediaGovernanceConfig();
+
+ assertThat(config.getTenantId()).isEqualTo("tenant_002");
+ assertThat(config.isEnabled()).isFalse();
+ assertThat(config.getAllowedAnalyzers()).isEmpty();
+ }
+
+ @Test
+ @DisplayName("should throw on server error")
+ void shouldThrowOnServerError() {
+ stubFor(get(urlEqualTo("/api/v1/media-governance/config"))
+ .willReturn(aResponse()
+ .withStatus(500)
+ .withHeader("Content-Type", "application/json")
+ .withBody("{\"error\": \"Internal server error\"}")));
+
+ assertThatThrownBy(() -> axonflow.getMediaGovernanceConfig())
+ .isInstanceOf(Exception.class);
+ }
+
+ @Test
+ @DisplayName("async should return future with config")
+ void asyncShouldReturnFuture() throws Exception {
+ stubFor(get(urlEqualTo("/api/v1/media-governance/config"))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/json")
+ .withBody(SAMPLE_CONFIG_JSON)));
+
+ CompletableFuture future = axonflow.getMediaGovernanceConfigAsync();
+ MediaGovernanceConfig config = future.get();
+
+ assertThat(config.getTenantId()).isEqualTo("tenant_001");
+ assertThat(config.isEnabled()).isTrue();
+ }
+ }
+
+ // ========================================================================
+ // updateMediaGovernanceConfig
+ // ========================================================================
+
+ @Nested
+ @DisplayName("updateMediaGovernanceConfig")
+ class UpdateMediaGovernanceConfig {
+
+ @Test
+ @DisplayName("should send PUT request and return updated config")
+ void shouldUpdateConfig() {
+ stubFor(put(urlEqualTo("/api/v1/media-governance/config"))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/json")
+ .withBody(SAMPLE_CONFIG_JSON)));
+
+ UpdateMediaGovernanceConfigRequest request = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(true)
+ .allowedAnalyzers(List.of("nsfw", "biometric", "ocr"))
+ .build();
+
+ MediaGovernanceConfig config = axonflow.updateMediaGovernanceConfig(request);
+
+ assertThat(config.getTenantId()).isEqualTo("tenant_001");
+ assertThat(config.isEnabled()).isTrue();
+ assertThat(config.getAllowedAnalyzers()).containsExactly("nsfw", "biometric", "ocr");
+
+ verify(putRequestedFor(urlEqualTo("/api/v1/media-governance/config"))
+ .withHeader("Content-Type", containing("application/json"))
+ .withRequestBody(containing("\"enabled\":true"))
+ .withRequestBody(containing("\"allowed_analyzers\"")));
+ }
+
+ @Test
+ @DisplayName("should send partial update with only enabled")
+ void shouldSendPartialUpdate() {
+ stubFor(put(urlEqualTo("/api/v1/media-governance/config"))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/json")
+ .withBody("{\"tenant_id\": \"tenant_001\", \"enabled\": false, \"allowed_analyzers\": [\"nsfw\"]}")));
+
+ UpdateMediaGovernanceConfigRequest request = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(false)
+ .build();
+
+ MediaGovernanceConfig config = axonflow.updateMediaGovernanceConfig(request);
+
+ assertThat(config.isEnabled()).isFalse();
+
+ // Verify null fields are not sent (NON_NULL inclusion)
+ verify(putRequestedFor(urlEqualTo("/api/v1/media-governance/config"))
+ .withRequestBody(containing("\"enabled\":false")));
+ }
+
+ @Test
+ @DisplayName("should require non-null request")
+ void shouldRequireNonNullRequest() {
+ assertThatThrownBy(() -> axonflow.updateMediaGovernanceConfig(null))
+ .isInstanceOf(NullPointerException.class)
+ .hasMessageContaining("request cannot be null");
+ }
+
+ @Test
+ @DisplayName("should throw on server error")
+ void shouldThrowOnServerError() {
+ stubFor(put(urlEqualTo("/api/v1/media-governance/config"))
+ .willReturn(aResponse()
+ .withStatus(403)
+ .withHeader("Content-Type", "application/json")
+ .withBody("{\"error\": \"Forbidden: insufficient permissions\"}")));
+
+ UpdateMediaGovernanceConfigRequest request = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(true)
+ .build();
+
+ assertThatThrownBy(() -> axonflow.updateMediaGovernanceConfig(request))
+ .isInstanceOf(Exception.class);
+ }
+
+ @Test
+ @DisplayName("async should return future with updated config")
+ void asyncShouldReturnFuture() throws Exception {
+ stubFor(put(urlEqualTo("/api/v1/media-governance/config"))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/json")
+ .withBody(SAMPLE_CONFIG_JSON)));
+
+ UpdateMediaGovernanceConfigRequest request = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(true)
+ .allowedAnalyzers(List.of("nsfw"))
+ .build();
+
+ CompletableFuture future =
+ axonflow.updateMediaGovernanceConfigAsync(request);
+ MediaGovernanceConfig config = future.get();
+
+ assertThat(config.isEnabled()).isTrue();
+ }
+ }
+
+ // ========================================================================
+ // getMediaGovernanceStatus
+ // ========================================================================
+
+ @Nested
+ @DisplayName("getMediaGovernanceStatus")
+ class GetMediaGovernanceStatus {
+
+ @Test
+ @DisplayName("should return media governance platform status")
+ void shouldReturnStatus() {
+ stubFor(get(urlEqualTo("/api/v1/media-governance/status"))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/json")
+ .withBody(SAMPLE_STATUS_JSON)));
+
+ MediaGovernanceStatus status = axonflow.getMediaGovernanceStatus();
+
+ assertThat(status.isAvailable()).isTrue();
+ assertThat(status.isEnabledByDefault()).isFalse();
+ assertThat(status.isPerTenantControl()).isTrue();
+ assertThat(status.getTier()).isEqualTo("enterprise");
+ }
+
+ @Test
+ @DisplayName("should return unavailable status")
+ void shouldReturnUnavailableStatus() {
+ stubFor(get(urlEqualTo("/api/v1/media-governance/status"))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/json")
+ .withBody("{\"available\": false, \"enabled_by_default\": false, \"per_tenant_control\": false, \"tier\": \"community\"}")));
+
+ MediaGovernanceStatus status = axonflow.getMediaGovernanceStatus();
+
+ assertThat(status.isAvailable()).isFalse();
+ assertThat(status.getTier()).isEqualTo("community");
+ }
+
+ @Test
+ @DisplayName("should throw on server error")
+ void shouldThrowOnServerError() {
+ stubFor(get(urlEqualTo("/api/v1/media-governance/status"))
+ .willReturn(aResponse()
+ .withStatus(500)
+ .withHeader("Content-Type", "application/json")
+ .withBody("{\"error\": \"Internal server error\"}")));
+
+ assertThatThrownBy(() -> axonflow.getMediaGovernanceStatus())
+ .isInstanceOf(Exception.class);
+ }
+
+ @Test
+ @DisplayName("async should return future with status")
+ void asyncShouldReturnFuture() throws Exception {
+ stubFor(get(urlEqualTo("/api/v1/media-governance/status"))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/json")
+ .withBody(SAMPLE_STATUS_JSON)));
+
+ CompletableFuture future = axonflow.getMediaGovernanceStatusAsync();
+ MediaGovernanceStatus status = future.get();
+
+ assertThat(status.isAvailable()).isTrue();
+ assertThat(status.getTier()).isEqualTo("enterprise");
+ }
+ }
+}
diff --git a/src/test/java/com/getaxonflow/sdk/types/MediaGovernanceTypesTest.java b/src/test/java/com/getaxonflow/sdk/types/MediaGovernanceTypesTest.java
new file mode 100644
index 0000000..b02e4ce
--- /dev/null
+++ b/src/test/java/com/getaxonflow/sdk/types/MediaGovernanceTypesTest.java
@@ -0,0 +1,524 @@
+/*
+ * Copyright 2026 AxonFlow
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.getaxonflow.sdk.types;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.getaxonflow.sdk.types.policies.PolicyTypes;
+import com.getaxonflow.sdk.types.policies.PolicyTypes.PolicyCategory;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.*;
+
+@DisplayName("Media Governance Types")
+class MediaGovernanceTypesTest {
+
+ private final ObjectMapper mapper = new ObjectMapper();
+
+ // ========================================================================
+ // MediaGovernanceConfig
+ // ========================================================================
+
+ @Nested
+ @DisplayName("MediaGovernanceConfig")
+ class MediaGovernanceConfigTests {
+
+ @Test
+ @DisplayName("should create with default constructor and set all fields")
+ void shouldCreateWithDefaultConstructor() {
+ MediaGovernanceConfig config = new MediaGovernanceConfig();
+ config.setTenantId("tenant_001");
+ config.setEnabled(true);
+ config.setAllowedAnalyzers(Arrays.asList("nsfw", "biometric", "ocr"));
+ config.setUpdatedAt("2026-02-18T10:00:00Z");
+ config.setUpdatedBy("admin@example.com");
+
+ assertThat(config.getTenantId()).isEqualTo("tenant_001");
+ assertThat(config.isEnabled()).isTrue();
+ assertThat(config.getAllowedAnalyzers()).containsExactly("nsfw", "biometric", "ocr");
+ assertThat(config.getUpdatedAt()).isEqualTo("2026-02-18T10:00:00Z");
+ assertThat(config.getUpdatedBy()).isEqualTo("admin@example.com");
+ }
+
+ @Test
+ @DisplayName("should handle disabled state")
+ void shouldHandleDisabledState() {
+ MediaGovernanceConfig config = new MediaGovernanceConfig();
+ config.setEnabled(false);
+ config.setAllowedAnalyzers(List.of());
+
+ assertThat(config.isEnabled()).isFalse();
+ assertThat(config.getAllowedAnalyzers()).isEmpty();
+ }
+
+ @Test
+ @DisplayName("should deserialize from JSON")
+ void shouldDeserializeFromJson() throws Exception {
+ String json = "{" +
+ "\"tenant_id\": \"tenant_abc\"," +
+ "\"enabled\": true," +
+ "\"allowed_analyzers\": [\"nsfw\", \"document\"]," +
+ "\"updated_at\": \"2026-02-18T12:00:00Z\"," +
+ "\"updated_by\": \"user@example.com\"" +
+ "}";
+
+ MediaGovernanceConfig config = mapper.readValue(json, MediaGovernanceConfig.class);
+
+ assertThat(config.getTenantId()).isEqualTo("tenant_abc");
+ assertThat(config.isEnabled()).isTrue();
+ assertThat(config.getAllowedAnalyzers()).containsExactly("nsfw", "document");
+ assertThat(config.getUpdatedAt()).isEqualTo("2026-02-18T12:00:00Z");
+ assertThat(config.getUpdatedBy()).isEqualTo("user@example.com");
+ }
+
+ @Test
+ @DisplayName("should ignore unknown properties during deserialization")
+ void shouldIgnoreUnknownProperties() throws Exception {
+ String json = "{\"tenant_id\": \"t1\", \"enabled\": false, \"future_field\": 42}";
+
+ MediaGovernanceConfig config = mapper.readValue(json, MediaGovernanceConfig.class);
+
+ assertThat(config.getTenantId()).isEqualTo("t1");
+ assertThat(config.isEnabled()).isFalse();
+ }
+
+ @Test
+ @DisplayName("should serialize to JSON")
+ void shouldSerializeToJson() throws Exception {
+ MediaGovernanceConfig config = new MediaGovernanceConfig();
+ config.setTenantId("tenant_xyz");
+ config.setEnabled(true);
+ config.setAllowedAnalyzers(List.of("nsfw"));
+
+ String json = mapper.writeValueAsString(config);
+
+ assertThat(json).contains("\"tenant_id\":\"tenant_xyz\"");
+ assertThat(json).contains("\"enabled\":true");
+ assertThat(json).contains("\"allowed_analyzers\":[\"nsfw\"]");
+ }
+
+ @Test
+ @DisplayName("equals should be reflexive")
+ void equalsShouldBeReflexive() {
+ MediaGovernanceConfig config = new MediaGovernanceConfig();
+ config.setTenantId("t1");
+ config.setEnabled(true);
+
+ assertThat(config).isEqualTo(config);
+ }
+
+ @Test
+ @DisplayName("equals should compare all fields")
+ void equalsShouldCompareAllFields() {
+ MediaGovernanceConfig config1 = new MediaGovernanceConfig();
+ config1.setTenantId("t1");
+ config1.setEnabled(true);
+ config1.setAllowedAnalyzers(List.of("nsfw"));
+ config1.setUpdatedAt("2026-02-18T10:00:00Z");
+ config1.setUpdatedBy("admin");
+
+ MediaGovernanceConfig config2 = new MediaGovernanceConfig();
+ config2.setTenantId("t1");
+ config2.setEnabled(true);
+ config2.setAllowedAnalyzers(List.of("nsfw"));
+ config2.setUpdatedAt("2026-02-18T10:00:00Z");
+ config2.setUpdatedBy("admin");
+
+ assertThat(config1).isEqualTo(config2);
+ assertThat(config1.hashCode()).isEqualTo(config2.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals should detect differences")
+ void equalsShouldDetectDifferences() {
+ MediaGovernanceConfig config1 = new MediaGovernanceConfig();
+ config1.setTenantId("t1");
+ config1.setEnabled(true);
+
+ MediaGovernanceConfig config2 = new MediaGovernanceConfig();
+ config2.setTenantId("t2");
+ config2.setEnabled(true);
+
+ MediaGovernanceConfig config3 = new MediaGovernanceConfig();
+ config3.setTenantId("t1");
+ config3.setEnabled(false);
+
+ assertThat(config1).isNotEqualTo(config2);
+ assertThat(config1).isNotEqualTo(config3);
+ assertThat(config1).isNotEqualTo(null);
+ assertThat(config1).isNotEqualTo("string");
+ }
+
+ @Test
+ @DisplayName("toString should include all fields")
+ void toStringShouldIncludeAllFields() {
+ MediaGovernanceConfig config = new MediaGovernanceConfig();
+ config.setTenantId("t1");
+ config.setEnabled(true);
+ config.setAllowedAnalyzers(List.of("nsfw", "biometric"));
+ config.setUpdatedAt("2026-02-18T10:00:00Z");
+ config.setUpdatedBy("admin");
+
+ String str = config.toString();
+
+ assertThat(str).contains("t1");
+ assertThat(str).contains("true");
+ assertThat(str).contains("nsfw");
+ assertThat(str).contains("biometric");
+ assertThat(str).contains("2026-02-18T10:00:00Z");
+ assertThat(str).contains("admin");
+ }
+ }
+
+ // ========================================================================
+ // MediaGovernanceStatus
+ // ========================================================================
+
+ @Nested
+ @DisplayName("MediaGovernanceStatus")
+ class MediaGovernanceStatusTests {
+
+ @Test
+ @DisplayName("should create with default constructor and set all fields")
+ void shouldCreateWithDefaultConstructor() {
+ MediaGovernanceStatus status = new MediaGovernanceStatus();
+ status.setAvailable(true);
+ status.setEnabledByDefault(false);
+ status.setPerTenantControl(true);
+ status.setTier("enterprise");
+
+ assertThat(status.isAvailable()).isTrue();
+ assertThat(status.isEnabledByDefault()).isFalse();
+ assertThat(status.isPerTenantControl()).isTrue();
+ assertThat(status.getTier()).isEqualTo("enterprise");
+ }
+
+ @Test
+ @DisplayName("should deserialize from JSON")
+ void shouldDeserializeFromJson() throws Exception {
+ String json = "{" +
+ "\"available\": true," +
+ "\"enabled_by_default\": true," +
+ "\"per_tenant_control\": false," +
+ "\"tier\": \"professional\"" +
+ "}";
+
+ MediaGovernanceStatus status = mapper.readValue(json, MediaGovernanceStatus.class);
+
+ assertThat(status.isAvailable()).isTrue();
+ assertThat(status.isEnabledByDefault()).isTrue();
+ assertThat(status.isPerTenantControl()).isFalse();
+ assertThat(status.getTier()).isEqualTo("professional");
+ }
+
+ @Test
+ @DisplayName("should ignore unknown properties during deserialization")
+ void shouldIgnoreUnknownProperties() throws Exception {
+ String json = "{\"available\": false, \"tier\": \"free\", \"unknown_field\": true}";
+
+ MediaGovernanceStatus status = mapper.readValue(json, MediaGovernanceStatus.class);
+
+ assertThat(status.isAvailable()).isFalse();
+ assertThat(status.getTier()).isEqualTo("free");
+ }
+
+ @Test
+ @DisplayName("should serialize to JSON")
+ void shouldSerializeToJson() throws Exception {
+ MediaGovernanceStatus status = new MediaGovernanceStatus();
+ status.setAvailable(true);
+ status.setEnabledByDefault(true);
+ status.setPerTenantControl(true);
+ status.setTier("enterprise");
+
+ String json = mapper.writeValueAsString(status);
+
+ assertThat(json).contains("\"available\":true");
+ assertThat(json).contains("\"enabled_by_default\":true");
+ assertThat(json).contains("\"per_tenant_control\":true");
+ assertThat(json).contains("\"tier\":\"enterprise\"");
+ }
+
+ @Test
+ @DisplayName("equals should be reflexive")
+ void equalsShouldBeReflexive() {
+ MediaGovernanceStatus status = new MediaGovernanceStatus();
+ status.setAvailable(true);
+
+ assertThat(status).isEqualTo(status);
+ }
+
+ @Test
+ @DisplayName("equals should compare all fields")
+ void equalsShouldCompareAllFields() {
+ MediaGovernanceStatus status1 = new MediaGovernanceStatus();
+ status1.setAvailable(true);
+ status1.setEnabledByDefault(false);
+ status1.setPerTenantControl(true);
+ status1.setTier("enterprise");
+
+ MediaGovernanceStatus status2 = new MediaGovernanceStatus();
+ status2.setAvailable(true);
+ status2.setEnabledByDefault(false);
+ status2.setPerTenantControl(true);
+ status2.setTier("enterprise");
+
+ assertThat(status1).isEqualTo(status2);
+ assertThat(status1.hashCode()).isEqualTo(status2.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals should detect differences")
+ void equalsShouldDetectDifferences() {
+ MediaGovernanceStatus status1 = new MediaGovernanceStatus();
+ status1.setAvailable(true);
+ status1.setTier("enterprise");
+
+ MediaGovernanceStatus status2 = new MediaGovernanceStatus();
+ status2.setAvailable(false);
+ status2.setTier("enterprise");
+
+ MediaGovernanceStatus status3 = new MediaGovernanceStatus();
+ status3.setAvailable(true);
+ status3.setTier("free");
+
+ assertThat(status1).isNotEqualTo(status2);
+ assertThat(status1).isNotEqualTo(status3);
+ assertThat(status1).isNotEqualTo(null);
+ assertThat(status1).isNotEqualTo("string");
+ }
+
+ @Test
+ @DisplayName("toString should include all fields")
+ void toStringShouldIncludeAllFields() {
+ MediaGovernanceStatus status = new MediaGovernanceStatus();
+ status.setAvailable(true);
+ status.setEnabledByDefault(false);
+ status.setPerTenantControl(true);
+ status.setTier("enterprise");
+
+ String str = status.toString();
+
+ assertThat(str).contains("true");
+ assertThat(str).contains("enterprise");
+ }
+ }
+
+ // ========================================================================
+ // UpdateMediaGovernanceConfigRequest
+ // ========================================================================
+
+ @Nested
+ @DisplayName("UpdateMediaGovernanceConfigRequest")
+ class UpdateMediaGovernanceConfigRequestTests {
+
+ @Test
+ @DisplayName("should create with default constructor and set fields")
+ void shouldCreateWithDefaultConstructor() {
+ UpdateMediaGovernanceConfigRequest request = new UpdateMediaGovernanceConfigRequest();
+ request.setEnabled(true);
+ request.setAllowedAnalyzers(List.of("nsfw", "ocr"));
+
+ assertThat(request.getEnabled()).isTrue();
+ assertThat(request.getAllowedAnalyzers()).containsExactly("nsfw", "ocr");
+ }
+
+ @Test
+ @DisplayName("should build with builder pattern")
+ void shouldBuildWithBuilder() {
+ UpdateMediaGovernanceConfigRequest request = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(true)
+ .allowedAnalyzers(List.of("nsfw", "biometric"))
+ .build();
+
+ assertThat(request.getEnabled()).isTrue();
+ assertThat(request.getAllowedAnalyzers()).containsExactly("nsfw", "biometric");
+ }
+
+ @Test
+ @DisplayName("builder should handle null enabled for partial update")
+ void builderShouldHandleNullEnabled() {
+ UpdateMediaGovernanceConfigRequest request = UpdateMediaGovernanceConfigRequest.builder()
+ .allowedAnalyzers(List.of("nsfw"))
+ .build();
+
+ assertThat(request.getEnabled()).isNull();
+ assertThat(request.getAllowedAnalyzers()).containsExactly("nsfw");
+ }
+
+ @Test
+ @DisplayName("builder should handle null allowedAnalyzers for partial update")
+ void builderShouldHandleNullAnalyzers() {
+ UpdateMediaGovernanceConfigRequest request = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(false)
+ .build();
+
+ assertThat(request.getEnabled()).isFalse();
+ assertThat(request.getAllowedAnalyzers()).isNull();
+ }
+
+ @Test
+ @DisplayName("should serialize omitting null fields")
+ void shouldSerializeOmittingNulls() throws Exception {
+ UpdateMediaGovernanceConfigRequest request = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(true)
+ .build();
+
+ String json = mapper.writeValueAsString(request);
+
+ assertThat(json).contains("\"enabled\":true");
+ assertThat(json).doesNotContain("allowed_analyzers");
+ }
+
+ @Test
+ @DisplayName("should serialize with all fields")
+ void shouldSerializeAllFields() throws Exception {
+ UpdateMediaGovernanceConfigRequest request = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(false)
+ .allowedAnalyzers(List.of("ocr"))
+ .build();
+
+ String json = mapper.writeValueAsString(request);
+
+ assertThat(json).contains("\"enabled\":false");
+ assertThat(json).contains("\"allowed_analyzers\":[\"ocr\"]");
+ }
+
+ @Test
+ @DisplayName("should deserialize from JSON")
+ void shouldDeserializeFromJson() throws Exception {
+ String json = "{\"enabled\": true, \"allowed_analyzers\": [\"nsfw\", \"biometric\"]}";
+
+ UpdateMediaGovernanceConfigRequest request =
+ mapper.readValue(json, UpdateMediaGovernanceConfigRequest.class);
+
+ assertThat(request.getEnabled()).isTrue();
+ assertThat(request.getAllowedAnalyzers()).containsExactly("nsfw", "biometric");
+ }
+
+ @Test
+ @DisplayName("equals should be reflexive")
+ void equalsShouldBeReflexive() {
+ UpdateMediaGovernanceConfigRequest request = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(true)
+ .build();
+
+ assertThat(request).isEqualTo(request);
+ }
+
+ @Test
+ @DisplayName("equals should compare all fields")
+ void equalsShouldCompareAllFields() {
+ UpdateMediaGovernanceConfigRequest r1 = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(true)
+ .allowedAnalyzers(List.of("nsfw"))
+ .build();
+
+ UpdateMediaGovernanceConfigRequest r2 = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(true)
+ .allowedAnalyzers(List.of("nsfw"))
+ .build();
+
+ assertThat(r1).isEqualTo(r2);
+ assertThat(r1.hashCode()).isEqualTo(r2.hashCode());
+ }
+
+ @Test
+ @DisplayName("equals should detect differences")
+ void equalsShouldDetectDifferences() {
+ UpdateMediaGovernanceConfigRequest r1 = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(true)
+ .build();
+
+ UpdateMediaGovernanceConfigRequest r2 = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(false)
+ .build();
+
+ assertThat(r1).isNotEqualTo(r2);
+ assertThat(r1).isNotEqualTo(null);
+ assertThat(r1).isNotEqualTo("string");
+ }
+
+ @Test
+ @DisplayName("toString should include fields")
+ void toStringShouldIncludeFields() {
+ UpdateMediaGovernanceConfigRequest request = UpdateMediaGovernanceConfigRequest.builder()
+ .enabled(true)
+ .allowedAnalyzers(List.of("nsfw", "biometric"))
+ .build();
+
+ String str = request.toString();
+
+ assertThat(str).contains("true");
+ assertThat(str).contains("nsfw");
+ assertThat(str).contains("biometric");
+ }
+ }
+
+ // ========================================================================
+ // Media Policy Category Constants & Enum Values
+ // ========================================================================
+
+ @Nested
+ @DisplayName("Media Policy Categories")
+ class MediaPolicyCategoryTests {
+
+ @Test
+ @DisplayName("CATEGORY_MEDIA_SAFETY constant should match enum value")
+ void mediaSafetyConstantShouldMatchEnum() {
+ assertThat(PolicyTypes.CATEGORY_MEDIA_SAFETY).isEqualTo("media-safety");
+ assertThat(PolicyCategory.MEDIA_SAFETY.getValue()).isEqualTo("media-safety");
+ assertThat(PolicyTypes.CATEGORY_MEDIA_SAFETY).isEqualTo(PolicyCategory.MEDIA_SAFETY.getValue());
+ }
+
+ @Test
+ @DisplayName("CATEGORY_MEDIA_BIOMETRIC constant should match enum value")
+ void mediaBiometricConstantShouldMatchEnum() {
+ assertThat(PolicyTypes.CATEGORY_MEDIA_BIOMETRIC).isEqualTo("media-biometric");
+ assertThat(PolicyCategory.MEDIA_BIOMETRIC.getValue()).isEqualTo("media-biometric");
+ assertThat(PolicyTypes.CATEGORY_MEDIA_BIOMETRIC).isEqualTo(PolicyCategory.MEDIA_BIOMETRIC.getValue());
+ }
+
+ @Test
+ @DisplayName("CATEGORY_MEDIA_DOCUMENT constant should match enum value")
+ void mediaDocumentConstantShouldMatchEnum() {
+ assertThat(PolicyTypes.CATEGORY_MEDIA_DOCUMENT).isEqualTo("media-document");
+ assertThat(PolicyCategory.MEDIA_DOCUMENT.getValue()).isEqualTo("media-document");
+ assertThat(PolicyTypes.CATEGORY_MEDIA_DOCUMENT).isEqualTo(PolicyCategory.MEDIA_DOCUMENT.getValue());
+ }
+
+ @Test
+ @DisplayName("CATEGORY_MEDIA_PII constant should match enum value")
+ void mediaPiiConstantShouldMatchEnum() {
+ assertThat(PolicyTypes.CATEGORY_MEDIA_PII).isEqualTo("media-pii");
+ assertThat(PolicyCategory.MEDIA_PII.getValue()).isEqualTo("media-pii");
+ assertThat(PolicyTypes.CATEGORY_MEDIA_PII).isEqualTo(PolicyCategory.MEDIA_PII.getValue());
+ }
+
+ @Test
+ @DisplayName("all media categories should exist in PolicyCategory enum")
+ void allMediaCategoriesShouldExist() {
+ assertThat(PolicyCategory.valueOf("MEDIA_SAFETY")).isNotNull();
+ assertThat(PolicyCategory.valueOf("MEDIA_BIOMETRIC")).isNotNull();
+ assertThat(PolicyCategory.valueOf("MEDIA_DOCUMENT")).isNotNull();
+ assertThat(PolicyCategory.valueOf("MEDIA_PII")).isNotNull();
+ }
+ }
+}