From 0718d109e02d75673c5e3bbbe1f726efea5481b7 Mon Sep 17 00:00:00 2001 From: Georg Lokowandt Date: Thu, 15 Oct 2026 00:33:44 +0200 Subject: [PATCH 1/4] add v3 feature flags API. Fix #1388 --- .../client/_ReactorCloudFoundryClient.java | 10 +- .../featureflags/ReactorFeatureFlagsV3.java | 80 +++++++++ .../client/v3/packages/ReactorPackages.java | 2 +- .../ReactorFeatureFlagsV3Test.java | 165 ++++++++++++++++++ .../client/v3/featureflags/GET_response.json | 27 +++ .../GET_{feature_flag_name}_response.json | 6 + .../PATCH_{feature_flag_name}_request.json | 4 + .../PATCH_{feature_flag_name}_response.json | 6 + .../client/CloudFoundryClient.java | 8 +- .../v3/featureflags/FeatureFlagsV3.java | 50 ++++++ .../featureflags/_GetFeatureFlagRequest.java | 35 ++++ .../featureflags/_GetFeatureFlagResponse.java | 56 ++++++ .../_ListFeatureFlagsRequest.java | 28 +++ .../_ListFeatureFlagsResponse.java | 30 ++++ .../_UpdateFeatureFlagRequest.java | 53 ++++++ .../_UpdateFeatureFlagResponse.java | 58 ++++++ .../GetFeatureFlagRequestTest.java | 34 ++++ .../ListFeatureFlagsRequestTest.java | 48 +++++ .../UpdateFeatureFlagRequestTest.java | 50 ++++++ .../client/v3/FeatureFlagsV3Test.java | 116 ++++++++++++ 20 files changed, 863 insertions(+), 3 deletions(-) create mode 100644 cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/featureflags/ReactorFeatureFlagsV3.java create mode 100644 cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/featureflags/ReactorFeatureFlagsV3Test.java create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_response.json create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_{feature_flag_name}_response.json create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_request.json create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_response.json create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/FeatureFlagsV3.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_GetFeatureFlagRequest.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_GetFeatureFlagResponse.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_ListFeatureFlagsRequest.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_ListFeatureFlagsResponse.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_UpdateFeatureFlagRequest.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_UpdateFeatureFlagResponse.java create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/featureflags/GetFeatureFlagRequestTest.java create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/featureflags/ListFeatureFlagsRequestTest.java create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/featureflags/UpdateFeatureFlagRequestTest.java create mode 100644 integration-test/src/test/java/org/cloudfoundry/client/v3/FeatureFlagsV3Test.java diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/_ReactorCloudFoundryClient.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/_ReactorCloudFoundryClient.java index 6fe80b2d96..2b4ef40efc 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/_ReactorCloudFoundryClient.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/_ReactorCloudFoundryClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 the original author or authors. + * Copyright 2013-2026 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,6 +58,7 @@ import org.cloudfoundry.client.v3.deployments.DeploymentsV3; import org.cloudfoundry.client.v3.domains.DomainsV3; import org.cloudfoundry.client.v3.droplets.Droplets; +import org.cloudfoundry.client.v3.featureflags.FeatureFlagsV3; import org.cloudfoundry.client.v3.isolationsegments.IsolationSegments; import org.cloudfoundry.client.v3.jobs.JobsV3; import org.cloudfoundry.client.v3.quotas.organizations.OrganizationQuotasV3; @@ -120,6 +121,7 @@ import org.cloudfoundry.reactor.client.v3.deployments.ReactorDeploymentsV3; import org.cloudfoundry.reactor.client.v3.domains.ReactorDomainsV3; import org.cloudfoundry.reactor.client.v3.droplets.ReactorDroplets; +import org.cloudfoundry.reactor.client.v3.featureflags.ReactorFeatureFlagsV3; import org.cloudfoundry.reactor.client.v3.isolationsegments.ReactorIsolationSegments; import org.cloudfoundry.reactor.client.v3.jobs.ReactorJobsV3; import org.cloudfoundry.reactor.client.v3.quotas.organizations.ReactorOrganizationQuotasV3; @@ -256,6 +258,12 @@ public FeatureFlags featureFlags() { return new ReactorFeatureFlags(getConnectionContext(), getRootV2(), getTokenProvider(), getRequestTags()); } + @Override + @Value.Derived + public FeatureFlagsV3 featureFlagsV3() { + return new ReactorFeatureFlagsV3(getConnectionContext(), getRootV3(), getTokenProvider(), getRequestTags()); + } + @Override @Value.Derived public Info info() { diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/featureflags/ReactorFeatureFlagsV3.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/featureflags/ReactorFeatureFlagsV3.java new file mode 100644 index 0000000000..30ac19fe90 --- /dev/null +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/featureflags/ReactorFeatureFlagsV3.java @@ -0,0 +1,80 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.reactor.client.v3.featureflags; + +import java.util.Map; +import org.cloudfoundry.client.v3.featureflags.FeatureFlagsV3; +import org.cloudfoundry.client.v3.featureflags.GetFeatureFlagRequest; +import org.cloudfoundry.client.v3.featureflags.GetFeatureFlagResponse; +import org.cloudfoundry.client.v3.featureflags.ListFeatureFlagsRequest; +import org.cloudfoundry.client.v3.featureflags.ListFeatureFlagsResponse; +import org.cloudfoundry.client.v3.featureflags.UpdateFeatureFlagRequest; +import org.cloudfoundry.client.v3.featureflags.UpdateFeatureFlagResponse; +import org.cloudfoundry.reactor.ConnectionContext; +import org.cloudfoundry.reactor.TokenProvider; +import org.cloudfoundry.reactor.client.v3.AbstractClientV3Operations; +import reactor.core.publisher.Mono; + +/** + * The Reactor-based implementation of {@link FeatureFlagsV3} + */ +public final class ReactorFeatureFlagsV3 extends AbstractClientV3Operations + implements FeatureFlagsV3 { + + /** + * Creates an instance + * + * @param connectionContext the {@link ConnectionContext} to use when communicating with the server + * @param root the root URI of the server. Typically something like {@code https://api.run.pivotal.io}. + * @param tokenProvider the {@link TokenProvider} to use when communicating with the server + * @param requestTags map with custom http headers which will be added to web request + */ + public ReactorFeatureFlagsV3( + ConnectionContext connectionContext, + Mono root, + TokenProvider tokenProvider, + Map requestTags) { + super(connectionContext, root, tokenProvider, requestTags); + } + + @Override + public Mono get(GetFeatureFlagRequest request) { + return get( + request, + GetFeatureFlagResponse.class, + builder -> builder.pathSegment("feature_flags", request.getName())) + .checkpoint(); + } + + @Override + public Mono list(ListFeatureFlagsRequest request) { + return get( + request, + ListFeatureFlagsResponse.class, + builder -> builder.pathSegment("feature_flags")) + .checkpoint(); + } + + @Override + public Mono update(UpdateFeatureFlagRequest request) { + return patch( + request, + UpdateFeatureFlagResponse.class, + builder -> builder.pathSegment("feature_flags", request.getName())) + .checkpoint(); + } +} diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/packages/ReactorPackages.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/packages/ReactorPackages.java index c28ea0d1a4..ea41c151c9 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/packages/ReactorPackages.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/packages/ReactorPackages.java @@ -128,7 +128,7 @@ public Mono listDroplets(ListPackageDropletsRequest public Mono upload(UploadPackageRequest request) { Path bits = request.getBits(); - if (bits.toFile().isDirectory()) { + if (bits != null && bits.toFile().isDirectory()) { return FileUtils.compress(bits) .map( temporaryFile -> diff --git a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/featureflags/ReactorFeatureFlagsV3Test.java b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/featureflags/ReactorFeatureFlagsV3Test.java new file mode 100644 index 0000000000..5d377624a9 --- /dev/null +++ b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/featureflags/ReactorFeatureFlagsV3Test.java @@ -0,0 +1,165 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.reactor.client.v3.featureflags; + +import static io.netty.handler.codec.http.HttpMethod.GET; +import static io.netty.handler.codec.http.HttpMethod.PATCH; +import static io.netty.handler.codec.http.HttpResponseStatus.OK; + +import java.time.Duration; +import java.util.Collections; +import org.cloudfoundry.client.v3.Link; +import org.cloudfoundry.client.v3.Pagination; +import org.cloudfoundry.client.v3.featureflags.GetFeatureFlagRequest; +import org.cloudfoundry.client.v3.featureflags.GetFeatureFlagResponse; +import org.cloudfoundry.client.v3.featureflags.ListFeatureFlagsRequest; +import org.cloudfoundry.client.v3.featureflags.ListFeatureFlagsResponse; +import org.cloudfoundry.client.v3.featureflags.UpdateFeatureFlagRequest; +import org.cloudfoundry.client.v3.featureflags.UpdateFeatureFlagResponse; +import org.cloudfoundry.reactor.InteractionContext; +import org.cloudfoundry.reactor.TestRequest; +import org.cloudfoundry.reactor.TestResponse; +import org.cloudfoundry.reactor.client.AbstractClientApiTest; +import org.junit.jupiter.api.Test; +import reactor.test.StepVerifier; + +final class ReactorFeatureFlagsV3Test extends AbstractClientApiTest { + + private static final String UPDATED_AT = "2020-03-10T15:49:32Z"; + + private final ReactorFeatureFlagsV3 featureFlags = + new ReactorFeatureFlagsV3( + CONNECTION_CONTEXT, this.root, TOKEN_PROVIDER, Collections.emptyMap()); + + @Test + void get() { + mockRequest( + InteractionContext.builder() + .request( + TestRequest.builder() + .method(GET) + .path("/feature_flags/app_scaling") + .build()) + .response( + TestResponse.builder() + .status(OK) + .payload( + "fixtures/client/v3/featureflags/GET_{feature_flag_name}_response.json") + .build()) + .build()); + + this.featureFlags + .get(GetFeatureFlagRequest.builder().name("app_scaling").build()) + .as(StepVerifier::create) + .expectNext( + GetFeatureFlagResponse.builder() + .name("app_scaling") + .enabled(true) + .updatedAt(UPDATED_AT) + .build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + @Test + void list() { + mockRequest( + InteractionContext.builder() + .request(TestRequest.builder().method(GET).path("/feature_flags").build()) + .response( + TestResponse.builder() + .status(OK) + .payload( + "fixtures/client/v3/featureflags/GET_response.json") + .build()) + .build()); + + this.featureFlags + .list(ListFeatureFlagsRequest.builder().build()) + .as(StepVerifier::create) + .expectNext( + ListFeatureFlagsResponse.builder() + .pagination( + Pagination.builder() + .totalResults(2) + .first( + Link.builder() + .href( + "https://api.example.org/v3/feature_flags?page=1&per_page=50") + .build()) + .last( + Link.builder() + .href( + "https://api.example.org/v3/feature_flags?page=1&per_page=50") + .build()) + .build()) + .resource( + GetFeatureFlagResponse.builder() + .name("app_scaling") + .enabled(true) + .updatedAt(UPDATED_AT) + .build()) + .resource( + GetFeatureFlagResponse.builder() + .name("user_org_creation") + .enabled(false) + .customErrorMessage("This feature is disabled") + .updatedAt(UPDATED_AT) + .build()) + .build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + @Test + void update() { + mockRequest( + InteractionContext.builder() + .request( + TestRequest.builder() + .method(PATCH) + .path("/feature_flags/app_scaling") + .payload( + "fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_request.json") + .build()) + .response( + TestResponse.builder() + .status(OK) + .payload( + "fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_response.json") + .build()) + .build()); + + this.featureFlags + .update( + UpdateFeatureFlagRequest.builder() + .name("app_scaling") + .enabled(false) + .customErrorMessage("This feature is disabled") + .build()) + .as(StepVerifier::create) + .expectNext( + UpdateFeatureFlagResponse.builder() + .name("app_scaling") + .enabled(false) + .customErrorMessage("This feature is disabled") + .updatedAt(UPDATED_AT) + .build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } +} diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_response.json new file mode 100644 index 0000000000..57bc921fd1 --- /dev/null +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_response.json @@ -0,0 +1,27 @@ +{ + "pagination": { + "total_results": 2, + "first": { + "href": "https://api.example.org/v3/feature_flags?page=1&per_page=50" + }, + "last": { + "href": "https://api.example.org/v3/feature_flags?page=1&per_page=50" + }, + "next": null, + "previous": null + }, + "resources": [ + { + "name": "app_scaling", + "enabled": true, + "custom_error_message": null, + "updated_at": "2020-03-10T15:49:32Z" + }, + { + "name": "user_org_creation", + "enabled": false, + "custom_error_message": "This feature is disabled", + "updated_at": "2020-03-10T15:49:32Z" + } + ] +} diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_{feature_flag_name}_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_{feature_flag_name}_response.json new file mode 100644 index 0000000000..f31c99d7b5 --- /dev/null +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_{feature_flag_name}_response.json @@ -0,0 +1,6 @@ +{ + "name": "app_scaling", + "enabled": true, + "custom_error_message": null, + "updated_at": "2020-03-10T15:49:32Z" +} diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_request.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_request.json new file mode 100644 index 0000000000..6ca4291987 --- /dev/null +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_request.json @@ -0,0 +1,4 @@ +{ + "enabled": false, + "custom_error_message": "This feature is disabled" +} diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_response.json new file mode 100644 index 0000000000..489ecbac7c --- /dev/null +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_response.json @@ -0,0 +1,6 @@ +{ + "name": "app_scaling", + "enabled": false, + "custom_error_message": "This feature is disabled", + "updated_at": "2020-03-10T15:49:32Z" +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/CloudFoundryClient.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/CloudFoundryClient.java index 3d587dcfe3..61c0ac2bac 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/CloudFoundryClient.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/CloudFoundryClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 the original author or authors. + * Copyright 2013-2026 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,6 +55,7 @@ import org.cloudfoundry.client.v3.deployments.DeploymentsV3; import org.cloudfoundry.client.v3.domains.DomainsV3; import org.cloudfoundry.client.v3.droplets.Droplets; +import org.cloudfoundry.client.v3.featureflags.FeatureFlagsV3; import org.cloudfoundry.client.v3.isolationsegments.IsolationSegments; import org.cloudfoundry.client.v3.jobs.JobsV3; import org.cloudfoundry.client.v3.organizations.OrganizationsV3; @@ -169,6 +170,11 @@ public interface CloudFoundryClient { */ FeatureFlags featureFlags(); + /** + * Main entry point to the Cloud Foundry Feature Flags V3 Client API + */ + FeatureFlagsV3 featureFlagsV3(); + /** * Main entry point to the Cloud Foundry Info Client API */ diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/FeatureFlagsV3.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/FeatureFlagsV3.java new file mode 100644 index 0000000000..f6a3a7f7c1 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/FeatureFlagsV3.java @@ -0,0 +1,50 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.client.v3.featureflags; + +import reactor.core.publisher.Mono; + +/** + * Main entry point to the Cloud Foundry Feature Flags V3 Client API + * see: https://v3-apidocs.cloudfoundry.org/#feature-flags + */ +public interface FeatureFlagsV3 { + + /** + * Makes the Get a Feature Flag request + * + * @param request the Get Feature Flag request + * @return the response from the Get Feature Flag request + */ + Mono get(GetFeatureFlagRequest request); + + /** + * Makes the List Feature Flags request + * + * @param request the List Feature Flags request + * @return the response from the List Feature Flags request + */ + Mono list(ListFeatureFlagsRequest request); + + /** + * Makes the Update a Feature Flag request + * + * @param request the Update Feature Flag request + * @return the response from the Update Feature Flag request + */ + Mono update(UpdateFeatureFlagRequest request); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_GetFeatureFlagRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_GetFeatureFlagRequest.java new file mode 100644 index 0000000000..bb90e40b49 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_GetFeatureFlagRequest.java @@ -0,0 +1,35 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.client.v3.featureflags; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.immutables.value.Value; + +/** + * The request payload for the Get Feature Flag operation + * + * see https://v3-apidocs.cloudfoundry.org/#get-a-feature-flag + */ +@Value.Immutable +abstract class _GetFeatureFlagRequest { + + /** + * The name of the feature flag + */ + @JsonIgnore + abstract String getName(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_GetFeatureFlagResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_GetFeatureFlagResponse.java new file mode 100644 index 0000000000..49a2ae84e9 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_GetFeatureFlagResponse.java @@ -0,0 +1,56 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.client.v3.featureflags; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.cloudfoundry.Nullable; +import org.immutables.value.Value; + +/** + * The response payload for the Get Feature Flag operation + */ +@JsonDeserialize +@Value.Immutable +abstract class _GetFeatureFlagResponse { + + /** + * The name of the feature flag + */ + @JsonProperty("name") + abstract String getName(); + + /** + * Whether the feature flag is enabled + */ + @JsonProperty("enabled") + abstract Boolean getEnabled(); + + /** + * The custom error message displayed to users when the flag is disabled + */ + @JsonProperty("custom_error_message") + @Nullable + abstract String getCustomErrorMessage(); + + /** + * The time the feature flag was last updated + */ + @JsonProperty("updated_at") + @Nullable + abstract String getUpdatedAt(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_ListFeatureFlagsRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_ListFeatureFlagsRequest.java new file mode 100644 index 0000000000..0c148fcab4 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_ListFeatureFlagsRequest.java @@ -0,0 +1,28 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.client.v3.featureflags; + +import org.cloudfoundry.client.v3.PaginatedRequest; +import org.immutables.value.Value; + +/** + * The request payload for the List Feature Flags operation + * + * see https://v3-apidocs.cloudfoundry.org/#list-feature-flags + */ +@Value.Immutable +abstract class _ListFeatureFlagsRequest extends PaginatedRequest {} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_ListFeatureFlagsResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_ListFeatureFlagsResponse.java new file mode 100644 index 0000000000..048dcf3ab8 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_ListFeatureFlagsResponse.java @@ -0,0 +1,30 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.client.v3.featureflags; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.cloudfoundry.client.v3.PaginatedResponse; +import org.immutables.value.Value; + +/** + * The response payload for the List Feature Flags operation + * + * see https://v3-apidocs.cloudfoundry.org/#list-feature-flags + */ +@JsonDeserialize +@Value.Immutable +abstract class _ListFeatureFlagsResponse extends PaginatedResponse {} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_UpdateFeatureFlagRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_UpdateFeatureFlagRequest.java new file mode 100644 index 0000000000..dddec0fc8b --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_UpdateFeatureFlagRequest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.client.v3.featureflags; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.cloudfoundry.Nullable; +import org.immutables.value.Value; + +/** + * The request payload for the Update Feature Flag operation + * + * see https://v3-apidocs.cloudfoundry.org/#update-a-feature-flag + */ +@JsonSerialize +@Value.Immutable +abstract class _UpdateFeatureFlagRequest { + + /** + * The name of the feature flag + */ + @JsonIgnore + abstract String getName(); + + /** + * Whether the feature flag is enabled + */ + @JsonProperty("enabled") + @Nullable + abstract Boolean getEnabled(); + + /** + * The custom error message displayed to users when the flag is disabled + */ + @JsonProperty("custom_error_message") + @Nullable + abstract String getCustomErrorMessage(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_UpdateFeatureFlagResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_UpdateFeatureFlagResponse.java new file mode 100644 index 0000000000..922f3c1a14 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_UpdateFeatureFlagResponse.java @@ -0,0 +1,58 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.client.v3.featureflags; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.cloudfoundry.Nullable; +import org.immutables.value.Value; + +/** + * The response payload for the Update Feature Flag operation + * + * see https://v3-apidocs.cloudfoundry.org/#update-a-feature-flag + */ +@JsonDeserialize +@Value.Immutable +abstract class _UpdateFeatureFlagResponse { + + /** + * The name of the feature flag + */ + @JsonProperty("name") + abstract String getName(); + + /** + * Whether the feature flag is enabled + */ + @JsonProperty("enabled") + abstract Boolean getEnabled(); + + /** + * The custom error message displayed to users when the flag is disabled + */ + @JsonProperty("custom_error_message") + @Nullable + abstract String getCustomErrorMessage(); + + /** + * The time the feature flag was last updated + */ + @JsonProperty("updated_at") + @Nullable + abstract String getUpdatedAt(); +} diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/featureflags/GetFeatureFlagRequestTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/featureflags/GetFeatureFlagRequestTest.java new file mode 100644 index 0000000000..4a8f7df210 --- /dev/null +++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/featureflags/GetFeatureFlagRequestTest.java @@ -0,0 +1,34 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.client.v3.featureflags; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +final class GetFeatureFlagRequestTest { + + @Test + void noName() { + assertThrows(IllegalStateException.class, () -> GetFeatureFlagRequest.builder().build()); + } + + @Test + void valid() { + GetFeatureFlagRequest.builder().name("app_scaling").build(); + } +} diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/featureflags/ListFeatureFlagsRequestTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/featureflags/ListFeatureFlagsRequestTest.java new file mode 100644 index 0000000000..7de69422ab --- /dev/null +++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/featureflags/ListFeatureFlagsRequestTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.client.v3.featureflags; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +final class ListFeatureFlagsRequestTest { + + @Test + void invalidPage() { + assertThrows( + IllegalStateException.class, + () -> ListFeatureFlagsRequest.builder().page(0).build()); + } + + @Test + void invalidPerPage() { + assertThrows( + IllegalStateException.class, + () -> ListFeatureFlagsRequest.builder().perPage(0).build()); + } + + @Test + void valid() { + ListFeatureFlagsRequest.builder().build(); + } + + @Test + void validWithPagination() { + ListFeatureFlagsRequest.builder().page(1).perPage(50).orderBy("name").build(); + } +} diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/featureflags/UpdateFeatureFlagRequestTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/featureflags/UpdateFeatureFlagRequestTest.java new file mode 100644 index 0000000000..d87b0946e0 --- /dev/null +++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/featureflags/UpdateFeatureFlagRequestTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.client.v3.featureflags; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +final class UpdateFeatureFlagRequestTest { + + @Test + void noName() { + assertThrows( + IllegalStateException.class, + () -> UpdateFeatureFlagRequest.builder().enabled(true).build()); + } + + @Test + void valid() { + UpdateFeatureFlagRequest.builder().name("app_scaling").enabled(true).build(); + } + + @Test + void validWithCustomErrorMessage() { + UpdateFeatureFlagRequest.builder() + .name("app_scaling") + .enabled(false) + .customErrorMessage("This feature is disabled") + .build(); + } + + @Test + void validNoFields() { + UpdateFeatureFlagRequest.builder().name("app_scaling").build(); + } +} diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/FeatureFlagsV3Test.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/FeatureFlagsV3Test.java new file mode 100644 index 0000000000..06d11d62f7 --- /dev/null +++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/FeatureFlagsV3Test.java @@ -0,0 +1,116 @@ +/* + * Copyright 2026 the original author or authors. + * + * 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 org.cloudfoundry.client.v3; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Duration; +import java.util.List; +import java.util.stream.Collectors; +import org.cloudfoundry.AbstractIntegrationTest; +import org.cloudfoundry.client.CloudFoundryClient; +import org.cloudfoundry.client.v3.featureflags.GetFeatureFlagRequest; +import org.cloudfoundry.client.v3.featureflags.GetFeatureFlagResponse; +import org.cloudfoundry.client.v3.featureflags.ListFeatureFlagsRequest; +import org.cloudfoundry.client.v3.featureflags.UpdateFeatureFlagRequest; +import org.cloudfoundry.util.PaginationUtils; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import reactor.test.StepVerifier; + +public class FeatureFlagsV3Test extends AbstractIntegrationTest { + + private static final String FLAG_NAME = "app_scaling"; + + @Autowired private CloudFoundryClient cloudFoundryClient; + + @Test + public void get() { + this.cloudFoundryClient + .featureFlagsV3() + .get(GetFeatureFlagRequest.builder().name(FLAG_NAME).build()) + .map(GetFeatureFlagResponse::getName) + .as(StepVerifier::create) + .expectNext(FLAG_NAME) + .expectComplete() + .verify(Duration.ofMinutes(5)); + } + + @Test + public void list() { + PaginationUtils.requestClientV3Resources( + page -> + this.cloudFoundryClient + .featureFlagsV3() + .list(ListFeatureFlagsRequest.builder().page(page).build())) + .map(GetFeatureFlagResponse::getName) + .collect(Collectors.toSet()) + .as(StepVerifier::create) + .consumeNextWith( + names -> + assertThat(names) + .containsAll( + List.of( + "app_bits_upload", + "app_scaling", + "diego_docker", + "private_domain_creation", + "route_creation", + "service_instance_creation", + "set_roles_by_username", + "unset_roles_by_username", + "user_org_creation"))) + .expectComplete() + .verify(Duration.ofMinutes(5)); + } + + @Test + public void update() { + this.cloudFoundryClient + .featureFlagsV3() + .get(GetFeatureFlagRequest.builder().name(FLAG_NAME).build()) + .flatMap( + original -> + this.cloudFoundryClient + .featureFlagsV3() + .update( + UpdateFeatureFlagRequest.builder() + .name(FLAG_NAME) + .enabled(!original.getEnabled()) + .build()) + .flatMap( + toggled -> + this.cloudFoundryClient + .featureFlagsV3() + .update( + UpdateFeatureFlagRequest + .builder() + .name(FLAG_NAME) + .enabled( + original + .getEnabled()) + .build()) + .thenReturn( + toggled.getEnabled() + != original + .getEnabled()))) + .as(StepVerifier::create) + .expectNext(true) + .expectComplete() + .verify(Duration.ofMinutes(5)); + } +} From 285d44989411f86da2ec9945b3c0c022bd540258 Mon Sep 17 00:00:00 2001 From: Georg Lokowandt Date: Thu, 15 Oct 2026 00:59:18 +0200 Subject: [PATCH 2/4] fix build with java 8 --- .../java/org/cloudfoundry/client/v3/FeatureFlagsV3Test.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/FeatureFlagsV3Test.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/FeatureFlagsV3Test.java index 06d11d62f7..a61d11bce7 100644 --- a/integration-test/src/test/java/org/cloudfoundry/client/v3/FeatureFlagsV3Test.java +++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/FeatureFlagsV3Test.java @@ -19,7 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat; import java.time.Duration; -import java.util.List; +import java.util.Arrays; import java.util.stream.Collectors; import org.cloudfoundry.AbstractIntegrationTest; import org.cloudfoundry.client.CloudFoundryClient; @@ -64,7 +64,7 @@ public void list() { names -> assertThat(names) .containsAll( - List.of( + Arrays.asList( "app_bits_upload", "app_scaling", "diego_docker", From f2c93fec416acc7ebb1c979e23ee192b47096143 Mon Sep 17 00:00:00 2001 From: Georg Lokowandt Date: Thu, 15 Oct 2026 01:08:37 +0200 Subject: [PATCH 3/4] fix spotless findings. --- .../src/test/java/org/cloudfoundry/client/v2/SpacesTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v2/SpacesTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v2/SpacesTest.java index e729b3d12a..4561f496e3 100644 --- a/integration-test/src/test/java/org/cloudfoundry/client/v2/SpacesTest.java +++ b/integration-test/src/test/java/org/cloudfoundry/client/v2/SpacesTest.java @@ -1888,7 +1888,8 @@ public void listServicesFilterByLabel() { @Test public void listServicesFilterByServiceBrokerId() { - List expectedValues = Arrays.asList(this.serviceName, this.serviceName + "-shareable"); + List expectedValues = + Arrays.asList(this.serviceName, this.serviceName + "-shareable"); Mono.zip(this.serviceBrokerId, this.spaceId) .flatMapMany( function( From 67fb15af1ec80d370b79faa8a8826f4033241432 Mon Sep 17 00:00:00 2001 From: Georg Lokowandt Date: Thu, 15 Oct 2026 17:53:11 +0200 Subject: [PATCH 4/4] fix unknown attribute 'links' --- .../v3/featureflags/ReactorFeatureFlagsV3Test.java | 9 +++++++++ .../client/v3/featureflags/GET_response.json | 14 ++++++++++++-- .../GET_{feature_flag_name}_response.json | 7 ++++++- .../PATCH_{feature_flag_name}_response.json | 7 ++++++- .../v3/featureflags/_GetFeatureFlagResponse.java | 11 +++++++++++ .../featureflags/_UpdateFeatureFlagResponse.java | 11 +++++++++++ 6 files changed, 55 insertions(+), 4 deletions(-) diff --git a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/featureflags/ReactorFeatureFlagsV3Test.java b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/featureflags/ReactorFeatureFlagsV3Test.java index 5d377624a9..82f54fd107 100644 --- a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/featureflags/ReactorFeatureFlagsV3Test.java +++ b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/featureflags/ReactorFeatureFlagsV3Test.java @@ -39,6 +39,7 @@ final class ReactorFeatureFlagsV3Test extends AbstractClientApiTest { + private static final String BASE_URL = "https://api.example.org/v3/feature_flags/"; private static final String UPDATED_AT = "2020-03-10T15:49:32Z"; private final ReactorFeatureFlagsV3 featureFlags = @@ -70,6 +71,7 @@ void get() { .name("app_scaling") .enabled(true) .updatedAt(UPDATED_AT) + .link("self", selfLink("app_scaling")) .build()) .expectComplete() .verify(Duration.ofSeconds(5)); @@ -112,6 +114,7 @@ void list() { .name("app_scaling") .enabled(true) .updatedAt(UPDATED_AT) + .link("self", selfLink("app_scaling")) .build()) .resource( GetFeatureFlagResponse.builder() @@ -119,6 +122,7 @@ void list() { .enabled(false) .customErrorMessage("This feature is disabled") .updatedAt(UPDATED_AT) + .link("self", selfLink("user_org_creation")) .build()) .build()) .expectComplete() @@ -158,8 +162,13 @@ void update() { .enabled(false) .customErrorMessage("This feature is disabled") .updatedAt(UPDATED_AT) + .link("self", selfLink("app_scaling")) .build()) .expectComplete() .verify(Duration.ofSeconds(5)); } + + private static Link selfLink(String flagName) { + return Link.builder().href(BASE_URL + flagName).build(); + } } diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_response.json index 57bc921fd1..1f3b39c0d9 100644 --- a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_response.json +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_response.json @@ -15,13 +15,23 @@ "name": "app_scaling", "enabled": true, "custom_error_message": null, - "updated_at": "2020-03-10T15:49:32Z" + "updated_at": "2020-03-10T15:49:32Z", + "links": { + "self": { + "href": "https://api.example.org/v3/feature_flags/app_scaling" + } + } }, { "name": "user_org_creation", "enabled": false, "custom_error_message": "This feature is disabled", - "updated_at": "2020-03-10T15:49:32Z" + "updated_at": "2020-03-10T15:49:32Z", + "links": { + "self": { + "href": "https://api.example.org/v3/feature_flags/user_org_creation" + } + } } ] } diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_{feature_flag_name}_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_{feature_flag_name}_response.json index f31c99d7b5..e4565f495a 100644 --- a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_{feature_flag_name}_response.json +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/GET_{feature_flag_name}_response.json @@ -2,5 +2,10 @@ "name": "app_scaling", "enabled": true, "custom_error_message": null, - "updated_at": "2020-03-10T15:49:32Z" + "updated_at": "2020-03-10T15:49:32Z", + "links": { + "self": { + "href": "https://api.example.org/v3/feature_flags/app_scaling" + } + } } diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_response.json index 489ecbac7c..4985c96c6f 100644 --- a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_response.json +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/featureflags/PATCH_{feature_flag_name}_response.json @@ -2,5 +2,10 @@ "name": "app_scaling", "enabled": false, "custom_error_message": "This feature is disabled", - "updated_at": "2020-03-10T15:49:32Z" + "updated_at": "2020-03-10T15:49:32Z", + "links": { + "self": { + "href": "https://api.example.org/v3/feature_flags/app_scaling" + } + } } diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_GetFeatureFlagResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_GetFeatureFlagResponse.java index 49a2ae84e9..c3d97a343c 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_GetFeatureFlagResponse.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_GetFeatureFlagResponse.java @@ -18,7 +18,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.Map; +import org.cloudfoundry.AllowNulls; import org.cloudfoundry.Nullable; +import org.cloudfoundry.client.v3.Link; import org.immutables.value.Value; /** @@ -53,4 +56,12 @@ abstract class _GetFeatureFlagResponse { @JsonProperty("updated_at") @Nullable abstract String getUpdatedAt(); + + /** + * Links to related resources and actions for the feature flag + */ + @AllowNulls + @JsonProperty("links") + @Nullable + abstract Map getLinks(); } diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_UpdateFeatureFlagResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_UpdateFeatureFlagResponse.java index 922f3c1a14..3ac12e07b9 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_UpdateFeatureFlagResponse.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/featureflags/_UpdateFeatureFlagResponse.java @@ -18,7 +18,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.util.Map; +import org.cloudfoundry.AllowNulls; import org.cloudfoundry.Nullable; +import org.cloudfoundry.client.v3.Link; import org.immutables.value.Value; /** @@ -55,4 +58,12 @@ abstract class _UpdateFeatureFlagResponse { @JsonProperty("updated_at") @Nullable abstract String getUpdatedAt(); + + /** + * Links to related resources and actions for the feature flag + */ + @AllowNulls + @JsonProperty("links") + @Nullable + abstract Map getLinks(); }