Skip to content

Commit

Permalink
Add update policy command
Browse files Browse the repository at this point in the history
  • Loading branch information
busybeetree committed Jul 27, 2023
1 parent b60e857 commit 0bdf3a0
Show file tree
Hide file tree
Showing 6 changed files with 422 additions and 2 deletions.
50 changes: 48 additions & 2 deletions docs/_docs/hivemq/policies.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mqtt hivemq policies
|---------|-------------------------------------|
| create | See [Create Policy](#create-policy) |
| get | See [Get Policy](#get-policy) |
| update | See [Update Policy](#update-policy) |
| list | See [List Policies](#list-policies) |
| delete | See [Delete Policy](#delete-policy) |

Expand Down Expand Up @@ -58,8 +59,8 @@ mqtt hivemq policies create --file my-policy.json

## Options

| Option | Long Version | Explanation | Required |
|--------|----------------|-----------------------------------------------------------------------------------------------------|-------------------------------------------------|
| Option | Long Version | Explanation | Required |
|--------|----------------|-----------------------------------------------------------------------------------------------------|:-----------------------------------------------:|
| | `--definition` | The definition of the policy. This should be a JSON string containing a complete policy definition. | Either `--definition` or `--file`, but not both |
| | `--file` | A path to a file containing the definition of the policy. | Either `--definition` or `--file`, but not both |

Expand Down Expand Up @@ -144,6 +145,51 @@ $ mqtt hivemq policies get --id my-policy-id

{% include options/help-options.md defaultHelp=true %}

***

# Update Policy

***

Update an existing policy.
The policy definition may be provided either directly from the command line or from a file.
The provided policy ID argument must match the ID in the policy definition.

```
mqtt hivemq policies update
```

***

## Simple Example

```
mqtt hivemq policies update --id my-policy-id --file my-policy.json
```

***

## Options

| Option | Long Version | Explanation | Required |
|--------|----------------|-----------------------------------------------------------------------------------------------------|:-----------------------------------------------:|
| `-i` | `--id` | The id of the policy to be updated. | X |
| | `--definition` | The definition of the policy. This should be a JSON string containing a complete policy definition. | Either `--definition` or `--file`, but not both |
| | `--file` | A path to a file containing the definition of the policy. | Either `--definition` or `--file`, but not both |

### API Connection Options

{% include options/api-connection-options.md %}

### Logging Options

{% include options/logging-options.md %}

### Help Options

{% include options/help-options.md defaultHelp=true %}


***

# List Policies
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright 2019-present HiveMQ and the HiveMQ Community
*
* 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.hivemq.cli.commands.hivemq.policies;

import com.google.gson.Gson;
import com.hivemq.cli.MqttCLIMain;
import com.hivemq.cli.commands.hivemq.datagovernance.DataGovernanceOptions;
import com.hivemq.cli.commands.hivemq.datagovernance.OutputFormatter;
import com.hivemq.cli.commands.hivemq.datagovernance.PolicyDefinitionOptions;
import com.hivemq.cli.hivemq.policies.UpdatePolicyTask;
import com.hivemq.cli.openapi.hivemq.DataGovernanceHubPoliciesApi;
import com.hivemq.cli.rest.HiveMQRestService;
import org.jetbrains.annotations.NotNull;
import org.tinylog.Logger;
import picocli.CommandLine;

import javax.inject.Inject;
import java.util.concurrent.Callable;

@CommandLine.Command(name = "update",
description = "Update an existing policy",
synopsisHeading = "%n@|bold Usage:|@ ",
descriptionHeading = "%n",
optionListHeading = "%n@|bold Options:|@%n",
commandListHeading = "%n@|bold Commands:|@%n",
versionProvider = MqttCLIMain.CLIVersionProvider.class,
mixinStandardHelpOptions = true)
public class UpdatePolicyCommand implements Callable<Integer> {

@SuppressWarnings({"unused", "NotNullFieldNotInitialized"})
@CommandLine.Option(names = {"-i", "--id"}, required = true, description = "The id of the policy")
private @NotNull String policyId;

@SuppressWarnings({"NotNullFieldNotInitialized", "unused"})
@CommandLine.ArgGroup(multiplicity = "1")
private @NotNull PolicyDefinitionOptions definitionOptions;

@CommandLine.Mixin
private final @NotNull DataGovernanceOptions dataGovernanceOptions = new DataGovernanceOptions();

private final @NotNull OutputFormatter outputFormatter;
private final @NotNull HiveMQRestService hiveMQRestService;
private final @NotNull Gson gson;

@Inject
public UpdatePolicyCommand(
final @NotNull HiveMQRestService hiveMQRestService,
final @NotNull OutputFormatter outputFormatter,
final @NotNull Gson gson) {
this.outputFormatter = outputFormatter;
this.hiveMQRestService = hiveMQRestService;
this.gson = gson;
}

@Override
public @NotNull Integer call() {
Logger.trace("Command {}", this);

final DataGovernanceHubPoliciesApi policiesApi =
hiveMQRestService.getPoliciesApi(dataGovernanceOptions.getUrl(), dataGovernanceOptions.getRateLimit());

if (policyId.isEmpty()) {
outputFormatter.printError("The policy id must not be empty.");
return 1;
}

final String definition = definitionOptions.getDefinition();
if (definition.isEmpty()) {
outputFormatter.printError("The policy definition must not be empty.");
return 1;
}

final UpdatePolicyTask updatePolicyTask =
new UpdatePolicyTask(outputFormatter, policiesApi, gson, policyId, definition);
if (updatePolicyTask.execute()) {
return 0;
} else {
return 1;
}
}

@Override
public @NotNull String toString() {
return "UpdatePolicyCommand{" +
"definitionOptions=" +
definitionOptions +
", dataGovernanceOptions=" +
dataGovernanceOptions +
", outputFormatter=" +
outputFormatter +
'}';
}
}
65 changes: 65 additions & 0 deletions src/main/java/com/hivemq/cli/hivemq/policies/UpdatePolicyTask.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2019-present HiveMQ and the HiveMQ Community
*
* 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.hivemq.cli.hivemq.policies;

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.hivemq.cli.commands.hivemq.datagovernance.OutputFormatter;
import com.hivemq.cli.openapi.ApiException;
import com.hivemq.cli.openapi.hivemq.DataGovernanceHubPoliciesApi;
import com.hivemq.cli.openapi.hivemq.Policy;
import org.jetbrains.annotations.NotNull;

public class UpdatePolicyTask {
private final @NotNull OutputFormatter outputFormatter;
private final @NotNull DataGovernanceHubPoliciesApi policiesApi;
private final @NotNull Gson gson;
private final @NotNull String policyId;
private final @NotNull String definition;

public UpdatePolicyTask(
final @NotNull OutputFormatter outputFormatter,
final @NotNull DataGovernanceHubPoliciesApi policiesApi,
final @NotNull Gson gson,
final @NotNull String policyId,
final @NotNull String definition) {
this.outputFormatter = outputFormatter;
this.policiesApi = policiesApi;
this.gson = gson;
this.policyId = policyId;
this.definition = definition;
}

public boolean execute() {
final Policy policy;
try {
policy = gson.fromJson(definition, Policy.class);
} catch (final JsonSyntaxException jsonSyntaxException) {
outputFormatter.printError("Could not parse policy JSON: " + jsonSyntaxException.getMessage());
return false;
}

try {
policiesApi.updatePolicy(policyId, policy);
} catch (final ApiException apiException) {
outputFormatter.printApiException("Failed to update policy", apiException);
return false;
}

return true;
}
}
3 changes: 3 additions & 0 deletions src/main/java/com/hivemq/cli/ioc/HiveMqModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.hivemq.cli.commands.hivemq.policies.GetPolicyCommand;
import com.hivemq.cli.commands.hivemq.policies.ListPoliciesCommand;
import com.hivemq.cli.commands.hivemq.policies.PoliciesCommand;
import com.hivemq.cli.commands.hivemq.policies.UpdatePolicyCommand;
import com.hivemq.cli.commands.hivemq.schemas.CreateSchemaCommand;
import com.hivemq.cli.commands.hivemq.schemas.DeleteSchemaCommand;
import com.hivemq.cli.commands.hivemq.schemas.GetSchemaCommand;
Expand All @@ -52,6 +53,7 @@ class HiveMqModule {
final @NotNull ExportClientsCommand exportClientsCommand,
final @NotNull PoliciesCommand policiesCommand,
final @NotNull GetPolicyCommand getPolicyCommand,
final @NotNull UpdatePolicyCommand updatePolicyCommand,
final @NotNull ListPoliciesCommand listPoliciesCommand,
final @NotNull CreatePolicyCommand createPolicyCommand,
final @NotNull DeletePolicyCommand deletePolicyCommand,
Expand All @@ -64,6 +66,7 @@ class HiveMqModule {
final @NotNull CommandErrorMessageHandler handler) {

final CommandLine policiesCommandLine = new CommandLine(policiesCommand).addSubcommand(getPolicyCommand)
.addSubcommand(updatePolicyCommand)
.addSubcommand(listPoliciesCommand)
.addSubcommand(createPolicyCommand)
.addSubcommand(deletePolicyCommand);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Copyright 2019-present HiveMQ and the HiveMQ Community
*
* 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.hivemq.cli.commands.hivemq.policies;

import com.google.gson.Gson;
import com.hivemq.cli.commands.hivemq.datagovernance.OutputFormatter;
import com.hivemq.cli.openapi.ApiException;
import com.hivemq.cli.openapi.hivemq.DataGovernanceHubPoliciesApi;
import com.hivemq.cli.rest.HiveMQRestService;
import com.hivemq.cli.utils.TestLoggerUtils;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import picocli.CommandLine;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyDouble;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class UpdatePolicyCommandTest {

private final @NotNull HiveMQRestService hiveMQRestService = mock(HiveMQRestService.class);
private final @NotNull Gson gson = new Gson();
private final @NotNull OutputFormatter outputFormatter = mock(OutputFormatter.class);
private final @NotNull DataGovernanceHubPoliciesApi policiesApi = mock(DataGovernanceHubPoliciesApi.class);

private final @NotNull CommandLine commandLine =
new CommandLine(new UpdatePolicyCommand(hiveMQRestService, outputFormatter, gson));

private static final @NotNull String POLICY_JSON =
"{ \"id\": \"policy-1\", \"matching\": { \"topicFilter\": \"a/#\" } }";

@BeforeEach
void setUp() {
TestLoggerUtils.resetLogger();
when(hiveMQRestService.getPoliciesApi(any(), anyDouble())).thenReturn(policiesApi);
}

@Test
void call_idMissing_error() {
assertEquals(2, commandLine.execute("--definition=" + POLICY_JSON));
}

@Test
void call_idEmpty_error() {
assertEquals(1, commandLine.execute("--id=", "--definition=" + POLICY_JSON));
verify(outputFormatter).printError(eq("The policy id must not be empty."));
}

@Test
void call_definitionMissing_error() {
assertEquals(2, commandLine.execute("--id=policy-1"));
}

@Test
void call_argumentDefinitionEmpty_error() {
assertEquals(1, commandLine.execute("--id=policy-1", "--definition="));
verify(outputFormatter).printError(eq("The policy definition must not be empty."));
}

@Test
void call_fileDefinitionEmpty_error() throws IOException {
final File policyFile = File.createTempFile("policy", ".json");
Files.write(policyFile.toPath(), "".getBytes());
assertEquals(1, commandLine.execute("--id=policy-1", "--file=" + policyFile.getAbsolutePath()));
verify(outputFormatter).printError(eq("The policy definition must not be empty."));
}

@Test
void call_bothFileAndArgumentDefinition_error() throws IOException {
final File policyFile = File.createTempFile("policy", ".json");
assertEquals(2,
commandLine.execute("--id=policy-1", "--definition='abc'", "--file=" + policyFile.getAbsolutePath()));
}

@Test
void call_urlAndRateLimitPassed_usedInApi() {
assertEquals(0,
commandLine.execute("--rate=123", "--url=test-url", "--id=policy-1", "--definition=" + POLICY_JSON));
verify(hiveMQRestService).getPoliciesApi(eq("test-url"), eq(123d));
}

@Test
void call_taskSuccessful_return0() throws ApiException {
assertEquals(0, commandLine.execute("--id=policy-1", "--definition=" + POLICY_JSON));
verify(policiesApi).updatePolicy(eq("policy-1"), any());
}

@Test
void call_taskFailed_return1() throws ApiException {
when(policiesApi.updatePolicy(eq("policy-1"), any())).thenThrow(ApiException.class);
assertEquals(1, commandLine.execute("--id=policy-1", "--definition=" + POLICY_JSON));
}
}
Loading

0 comments on commit 0bdf3a0

Please sign in to comment.