This is an automated email from the ASF dual-hosted git repository.
sk0x50 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new bb4d83f584 IGNITE-18097 CLI should check if it's already connected
before trying to connect. Fixes #1404
bb4d83f584 is described below
commit bb4d83f5849808c42e5c2102b77e3b42a935cd5c
Author: Vadim Pakhnushev <[email protected]>
AuthorDate: Fri Dec 23 15:05:18 2022 +0200
IGNITE-18097 CLI should check if it's already connected before trying to
connect. Fixes #1404
Signed-off-by: Slava Koptilin <[email protected]>
---
...liCommandTestNotInitializedIntegrationBase.java | 6 +++-
.../cli/commands/connect/ItConnectCommandTest.java | 28 +++++++++++++++
.../commands/questions/ItConnectToClusterTest.java | 39 ++++++++++++++++++++
.../internal/cli/call/connect/ConnectCall.java | 9 +++--
.../cli/commands/connect/ConnectReplCommand.java | 17 +++++----
.../questions/ConnectToClusterQuestion.java | 42 ++++++++++++++--------
.../internal/cli/core/flow/builder/Flows.java | 9 +++--
7 files changed, 121 insertions(+), 29 deletions(-)
diff --git
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/CliCommandTestNotInitializedIntegrationBase.java
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/CliCommandTestNotInitializedIntegrationBase.java
index ba3ce092a4..c185b3866e 100644
---
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/CliCommandTestNotInitializedIntegrationBase.java
+++
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/CliCommandTestNotInitializedIntegrationBase.java
@@ -81,11 +81,15 @@ public class CliCommandTestNotInitializedIntegrationBase
extends IntegrationTest
cmd = new CommandLine(getCommandClass(), new MicronautFactory(context))
.registerConverter(NodeNameOrUrl.class, new
NodeNameOrUrlConverter(nodeNameRegistry));
cmd.setDefaultValueProvider(configDefaultValueProvider);
+ resetOutput();
+ CommandLineContextProvider.setCmd(cmd);
+ }
+
+ protected void resetOutput() {
sout = new StringWriter();
serr = new StringWriter();
cmd.setOut(new PrintWriter(sout));
cmd.setErr(new PrintWriter(serr));
- CommandLineContextProvider.setCmd(cmd);
}
@BeforeAll
diff --git
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/connect/ItConnectCommandTest.java
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/connect/ItConnectCommandTest.java
index 75267cf256..123d45319b 100644
---
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/connect/ItConnectCommandTest.java
+++
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/connect/ItConnectCommandTest.java
@@ -107,6 +107,34 @@ class ItConnectCommandTest extends
CliCommandTestInitializedIntegrationBase {
assertThat(promptAfter).isEqualTo("[disconnected]> ");
}
+ @Test
+ @DisplayName("Should state that already connected")
+ void connectTwice() {
+ // Given connected to cluster
+ execute("connect");
+ // And output is
+ assertAll(
+ this::assertErrOutputIsEmpty,
+ () -> assertOutputIs("Connected to http://localhost:10300" +
System.lineSeparator())
+ );
+ // And prompt is
+ String promptBefore = Ansi.OFF.string(promptProvider.getPrompt());
+ assertThat(promptBefore).isEqualTo("[" + nodeName() + "]> ");
+
+ // When connect again
+ resetOutput();
+ execute("connect");
+
+ // Then
+ assertAll(
+ this::assertErrOutputIsEmpty,
+ () -> assertOutputIs("You are already connected to
http://localhost:10300" + System.lineSeparator())
+ );
+ // And prompt is still connected
+ String promptAfter = Ansi.OFF.string(promptProvider.getPrompt());
+ assertThat(promptAfter).isEqualTo("[" + nodeName() + "]> ");
+ }
+
private String nodeName() {
return CLUSTER_NODES.get(0).name();
}
diff --git
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToClusterTest.java
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToClusterTest.java
index 3df96fe8d6..1adfaae91c 100644
---
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToClusterTest.java
+++
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/questions/ItConnectToClusterTest.java
@@ -27,6 +27,7 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import
org.apache.ignite.internal.cli.commands.CliCommandTestInitializedIntegrationBase;
+import org.apache.ignite.internal.cli.commands.TopLevelCliReplCommand;
import
org.apache.ignite.internal.cli.commands.cliconfig.TestConfigManagerHelper;
import org.apache.ignite.internal.cli.config.ConfigConstants;
import org.apache.ignite.internal.cli.config.TestStateConfigHelper;
@@ -58,6 +59,11 @@ class ItConnectToClusterTest extends
CliCommandTestInitializedIntegrationBase {
private Terminal terminal;
private Path input;
+ @Override
+ protected Class<?> getCommandClass() {
+ return TopLevelCliReplCommand.class;
+ }
+
@Override
@BeforeEach
public void setUp(TestInfo testInfo) throws Exception {
@@ -132,6 +138,39 @@ class ItConnectToClusterTest extends
CliCommandTestInitializedIntegrationBase {
.isEqualTo("http://localhost:10300");
}
+ @Test
+ @DisplayName("Should ask to connect to different URL")
+ void connectToAnotherUrl() throws IOException {
+ // Given prompt before connect
+ String promptBefore = Ansi.OFF.string(promptProvider.getPrompt());
+ assertThat(promptBefore).isEqualTo("[disconnected]> ");
+
+ // And connected
+ execute("connect");
+
+ // And output is
+ assertAll(
+ this::assertErrOutputIsEmpty,
+ () -> assertOutputIs("Connected to http://localhost:10300" +
System.lineSeparator())
+ );
+
+ // And answer is "y"
+ bindAnswers("y");
+
+ // When connect to different URL
+ resetOutput();
+ execute("connect", "http://localhost:10301");
+
+ // Then
+ assertAll(
+ this::assertErrOutputIsEmpty,
+ () -> assertOutputIs("Connected to http://localhost:10301" +
System.lineSeparator())
+ );
+ // And prompt is changed to another node
+ String promptAfter = Ansi.OFF.string(promptProvider.getPrompt());
+ assertThat(promptAfter).isEqualTo("[" + CLUSTER_NODES.get(1).name() +
"]> ");
+ }
+
private String nodeName() {
return CLUSTER_NODES.get(0).name();
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/connect/ConnectCall.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/connect/ConnectCall.java
index a29401da1e..506182f81d 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/connect/ConnectCall.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/connect/ConnectCall.java
@@ -21,6 +21,7 @@ import com.google.gson.Gson;
import jakarta.inject.Singleton;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.Objects;
import org.apache.ignite.internal.cli.NodeNameRegistry;
import org.apache.ignite.internal.cli.config.ConfigConstants;
import org.apache.ignite.internal.cli.config.StateConfigProvider;
@@ -60,8 +61,12 @@ public class ConnectCall implements Call<ConnectCallInput,
String> {
@Override
public CallOutput<String> execute(ConnectCallInput input) {
+ String nodeUrl = input.getNodeUrl();
+ if (session.isConnectedToNode() && Objects.equals(session.nodeUrl(),
nodeUrl)) {
+ MessageUiComponent message = MessageUiComponent.fromMessage("You
are already connected to %s", UiElements.url(nodeUrl));
+ return DefaultCallOutput.success(message.render());
+ }
try {
- String nodeUrl = input.getNodeUrl();
String configuration = fetchNodeConfiguration(nodeUrl);
session.setNodeName(fetchNodeName(nodeUrl));
session.setNodeUrl(nodeUrl);
@@ -73,7 +78,7 @@ public class ConnectCall implements Call<ConnectCallInput,
String> {
} catch (ApiException | IllegalArgumentException e) {
session.setConnectedToNode(false);
- return DefaultCallOutput.failure(new IgniteCliApiException(e,
input.getNodeUrl()));
+ return DefaultCallOutput.failure(new IgniteCliApiException(e,
nodeUrl));
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectReplCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectReplCommand.java
index db12b83720..55cd5c962e 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectReplCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/connect/ConnectReplCommand.java
@@ -25,7 +25,8 @@ import
org.apache.ignite.internal.cli.call.connect.ConnectCall;
import org.apache.ignite.internal.cli.call.connect.ConnectCallInput;
import org.apache.ignite.internal.cli.commands.BaseCommand;
import org.apache.ignite.internal.cli.commands.node.NodeNameOrUrl;
-import org.apache.ignite.internal.cli.core.call.CallExecutionPipeline;
+import
org.apache.ignite.internal.cli.commands.questions.ConnectToClusterQuestion;
+import org.apache.ignite.internal.cli.core.flow.builder.Flows;
import picocli.CommandLine.Command;
import picocli.CommandLine.Parameters;
@@ -42,15 +43,17 @@ public class ConnectReplCommand extends BaseCommand
implements Runnable {
@Inject
private ConnectCall connectCall;
+ @Inject
+ private ConnectToClusterQuestion question;
+
/** {@inheritDoc} */
@Override
public void run() {
- CallExecutionPipeline.builder(connectCall)
- .inputProvider(() -> new
ConnectCallInput(nodeNameOrUrl.stringUrl()))
- .output(spec.commandLine().getOut())
- .errOutput(spec.commandLine().getErr())
+ question.askQuestionIfConnected(nodeNameOrUrl.stringUrl())
+ .map(ConnectCallInput::new)
+ .then(Flows.fromCall(connectCall))
.verbose(verbose)
- .build()
- .runPipeline();
+ .print()
+ .start();
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/questions/ConnectToClusterQuestion.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/questions/ConnectToClusterQuestion.java
index b5743fa014..40304184e1 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/questions/ConnectToClusterQuestion.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/questions/ConnectToClusterQuestion.java
@@ -51,12 +51,17 @@ public class ConnectToClusterQuestion {
/**
- * Execute call with question about connect to cluster in case when
disconnected state.
+ * Asks whether the user wants to connect to the default node when user
hasn't passed a URL explicitly and we're not connected.
*
* @param clusterUrl cluster url.
- * @return {@link FlowBuilder} instance with question in case when cluster
url.
+ * @return {@link FlowBuilder} instance which returns a URL.
*/
public FlowBuilder<Void, String> askQuestionIfNotConnected(String
clusterUrl) {
+ String url = clusterUrlOrSessionNode(clusterUrl);
+ if (url != null) {
+ return Flows.from(url);
+ }
+
String defaultUrl =
configManagerProvider.get().getCurrentProperty(ConfigConstants.CLUSTER_URL);
QuestionUiComponent questionUiComponent =
QuestionUiComponent.fromQuestion(
@@ -64,24 +69,33 @@ public class ConnectToClusterQuestion {
UiElements.url(defaultUrl), UiElements.yesNo()
);
- return Flows.from(clusterUrlOrSessionNode(clusterUrl))
- .flatMap(v -> {
- if (Objects.isNull(v)) {
- return Flows.<String,
ConnectCallInput>acceptQuestion(questionUiComponent,
- () -> new ConnectCallInput(defaultUrl))
- .then(Flows.fromCall(connectCall))
- .print()
- .map(ignored ->
clusterUrlOrSessionNode(clusterUrl));
- } else {
- return Flows.identity();
- }
- });
+ return Flows.<Void,
ConnectCallInput>acceptQuestion(questionUiComponent, () -> new
ConnectCallInput(defaultUrl))
+ .then(Flows.fromCall(connectCall))
+ .print()
+ .map(ignored -> session.nodeUrl());
}
private String clusterUrlOrSessionNode(String clusterUrl) {
return clusterUrl != null ? clusterUrl : session.nodeUrl();
}
+ /**
+ * Ask if the user really wants to connect if we are already connected and
the URL is different.
+ *
+ * @param clusterUrl cluster url.
+ * @return {@link FlowBuilder} instance with question in case when cluster
url.
+ */
+ public FlowBuilder<Void, String> askQuestionIfConnected(String clusterUrl)
{
+ if (session.isConnectedToNode() && !Objects.equals(session.nodeUrl(),
clusterUrl)) {
+ QuestionUiComponent question = QuestionUiComponent.fromQuestion(
+ "You are already connected to the %s, do you want to
connect to the %s? %s ",
+ UiElements.url(session.nodeUrl()),
UiElements.url(clusterUrl), UiElements.yesNo()
+ );
+ return Flows.acceptQuestion(question, () -> clusterUrl);
+ }
+ return Flows.from(clusterUrl);
+ }
+
/**
* Ask for connect to the cluster and suggest to save the last connected
URL as default.
*/
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/builder/Flows.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/builder/Flows.java
index 2f98bfe9c2..cf94f792c0 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/builder/Flows.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/flow/builder/Flows.java
@@ -133,11 +133,10 @@ public final class Flows {
* @return new {@link FlowBuilder}.
*/
public static <I, O> FlowBuilder<I, O> acceptQuestion(String question,
Supplier<O> onAccept) {
- return Flows.<I, O>question(question,
- List.of(new AcceptedQuestionAnswer<>((a, i) -> null),
- new InterruptQuestionAnswer<>())
- )
- .then(mono(unused -> onAccept.get()));
+ return question(question,
+ List.of(new AcceptedQuestionAnswer<>((a, i) -> onAccept.get()),
+ new InterruptQuestionAnswer<>())
+ );
}
/**