This is an automated email from the ASF dual-hosted git repository.

apkhmv 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 4da2b8ec59 IGNITE-19316 Fix ItIgnitePicocliCommandsTest (#2008)
4da2b8ec59 is described below

commit 4da2b8ec5905641a61ecf45a11658939ef2391ca
Author: Aleksandr Pakhomov <[email protected]>
AuthorDate: Wed May 3 16:02:10 2023 +0400

    IGNITE-19316 Fix ItIgnitePicocliCommandsTest (#2008)
    
    ---------
    
    Co-authored-by: Vadim Pakhnushev <[email protected]>
---
 .../repl/executor/ItIgnitePicocliCommandsTest.java |  2 -
 .../registry/impl/ClusterConfigRegistryImpl.java   | 28 ++++-----
 .../repl/registry/impl/JdbcUrlRegistryImpl.java    |  4 +-
 .../cli/core/repl/registry/impl/LazyObjectRef.java | 69 ++++++++++++++++++++++
 .../repl/registry/impl/MetricRegistryImpl.java     | 33 +++++------
 .../repl/registry/impl/NodeConfigRegistryImpl.java | 29 ++++-----
 .../repl/registry/impl/NodeNameRegistryImpl.java   |  4 +-
 .../core/repl/registry/impl/UnitsRegistryImpl.java | 37 +++++++-----
 .../core/repl/registry/impl/LazyObjectRefTest.java | 61 +++++++++++++++++++
 9 files changed, 196 insertions(+), 71 deletions(-)

diff --git 
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/core/repl/executor/ItIgnitePicocliCommandsTest.java
 
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/core/repl/executor/ItIgnitePicocliCommandsTest.java
index 4d256fc364..2586a36d0e 100644
--- 
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/core/repl/executor/ItIgnitePicocliCommandsTest.java
+++ 
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/core/repl/executor/ItIgnitePicocliCommandsTest.java
@@ -52,7 +52,6 @@ import org.jline.reader.ParsedLine;
 import org.jline.reader.impl.DefaultParser;
 import org.jline.reader.impl.completer.SystemCompleter;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Named;
 import org.junit.jupiter.api.Test;
@@ -63,7 +62,6 @@ import org.junit.jupiter.params.provider.MethodSource;
 import org.mockito.Mockito;
 
 /** Integration test for all completions in interactive mode. */
-@Disabled("IGNITE-19351")
 public class ItIgnitePicocliCommandsTest extends 
CliCommandTestInitializedIntegrationBase {
 
     private static final String DEFAULT_REST_URL = "http://localhost:10300";;
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/ClusterConfigRegistryImpl.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/ClusterConfigRegistryImpl.java
index 292ac24148..e6034c5d86 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/ClusterConfigRegistryImpl.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/ClusterConfigRegistryImpl.java
@@ -20,8 +20,6 @@ package 
org.apache.ignite.internal.cli.core.repl.registry.impl;
 import com.typesafe.config.Config;
 import com.typesafe.config.ConfigFactory;
 import jakarta.inject.Singleton;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.atomic.AtomicReference;
 import org.apache.ignite.internal.cli.call.configuration.ClusterConfigShowCall;
 import 
org.apache.ignite.internal.cli.call.configuration.ClusterConfigShowCallInput;
 import org.apache.ignite.internal.cli.core.repl.AsyncSessionEventListener;
@@ -34,7 +32,7 @@ public class ClusterConfigRegistryImpl implements 
ClusterConfigRegistry, AsyncSe
 
     private final ClusterConfigShowCall clusterConfigShowCall;
 
-    private final AtomicReference<Config> config = new AtomicReference<>(null);
+    private LazyObjectRef<Config> configRef;
 
     public ClusterConfigRegistryImpl(ClusterConfigShowCall 
clusterConfigShowCall) {
         this.clusterConfigShowCall = clusterConfigShowCall;
@@ -42,27 +40,25 @@ public class ClusterConfigRegistryImpl implements 
ClusterConfigRegistry, AsyncSe
 
     @Override
     public void onConnect(SessionInfo sessionInfo) {
-        CompletableFuture.runAsync(() -> {
-            try {
-                config.set(ConfigFactory.parseString(
-                        clusterConfigShowCall.execute(
-                                
ClusterConfigShowCallInput.builder().clusterUrl(sessionInfo.nodeUrl()).build()
-                        ).body().getValue()
-                ));
-            } catch (Exception ignored) {
-                // no-op
-            }
-        });
+        configRef = new LazyObjectRef<>(() -> fetchConfig(sessionInfo));
+    }
+
+    private Config fetchConfig(SessionInfo sessionInfo) {
+        return ConfigFactory.parseString(
+                clusterConfigShowCall.execute(
+                        
ClusterConfigShowCallInput.builder().clusterUrl(sessionInfo.nodeUrl()).build()
+                ).body().getValue()
+        );
     }
 
     @Override
     public void onDisconnect() {
-
+        configRef = null;
     }
 
     /** {@inheritDoc} */
     @Override
     public Config config() {
-        return config.get();
+        return configRef == null ? null : configRef.get();
     }
 }
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/JdbcUrlRegistryImpl.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/JdbcUrlRegistryImpl.java
index 80b6fc3d15..aa3711fab3 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/JdbcUrlRegistryImpl.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/JdbcUrlRegistryImpl.java
@@ -91,7 +91,7 @@ public class JdbcUrlRegistryImpl implements JdbcUrlRegistry, 
AsyncSessionEventLi
     }
 
     @Override
-    public void onConnect(SessionInfo sessionInfo) {
+    public synchronized void onConnect(SessionInfo sessionInfo) {
         if (executor == null) {
             executor = Executors.newSingleThreadScheduledExecutor(new 
NamedThreadFactory("JdbcUrlRegistry", log));
             executor.scheduleWithFixedDelay(this::fetchJdbcUrls, 0, 5, 
TimeUnit.SECONDS);
@@ -99,7 +99,7 @@ public class JdbcUrlRegistryImpl implements JdbcUrlRegistry, 
AsyncSessionEventLi
     }
 
     @Override
-    public void onDisconnect() {
+    public synchronized void onDisconnect() {
         if (executor != null) {
             shutdownAndAwaitTermination(executor, 3, TimeUnit.SECONDS);
             executor = null;
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/LazyObjectRef.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/LazyObjectRef.java
new file mode 100644
index 0000000000..52df897149
--- /dev/null
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/LazyObjectRef.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.ignite.internal.cli.core.repl.registry.impl;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+import org.apache.ignite.internal.cli.logger.CliLoggers;
+import org.apache.ignite.internal.logger.IgniteLogger;
+import org.jetbrains.annotations.Nullable;
+
+/** Lazy async reference that will fetch the value from the source until the 
value is not null. */
+public final class LazyObjectRef<R> {
+
+    private static final IgniteLogger LOG = 
CliLoggers.forClass(LazyObjectRef.class);
+
+    private final Supplier<R> source;
+
+    private final AtomicReference<R> ref = new AtomicReference<>(null);
+
+    private final AtomicReference<Boolean> execInProgress = new 
AtomicReference<>(false);
+
+    public LazyObjectRef(Supplier<R> source) {
+        this.source = source;
+        fetchFrom(source);
+    }
+
+    private void fetchFrom(Supplier<R> source) {
+        execInProgress.set(true);
+
+        CompletableFuture.supplyAsync(source)
+                .thenAccept(ref::set)
+                .whenComplete((v, t) -> {
+                    if (t != null) {
+                        LOG.warn("Got exception when fetch from source", t);
+                    }
+                    execInProgress.set(false);
+                });
+    }
+
+    /** Returns {@code null} if the fetching is in progress or the value 
returned from the source is {@code null}. */
+    @Nullable
+    public R get() {
+        if (ref.get() == null && execInProgress.get()) {
+            return null;
+        }
+
+        if (ref.get() == null && !execInProgress.get()) {
+            fetchFrom(source);
+        }
+
+        return ref.get();
+    }
+}
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/MetricRegistryImpl.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/MetricRegistryImpl.java
index f194120215..72422a16dc 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/MetricRegistryImpl.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/MetricRegistryImpl.java
@@ -20,13 +20,13 @@ package 
org.apache.ignite.internal.cli.core.repl.registry.impl;
 import jakarta.inject.Inject;
 import jakarta.inject.Singleton;
 import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
 import 
org.apache.ignite.internal.cli.call.node.metric.NodeMetricSourceListCall;
 import org.apache.ignite.internal.cli.core.call.UrlCallInput;
 import org.apache.ignite.internal.cli.core.repl.AsyncSessionEventListener;
 import org.apache.ignite.internal.cli.core.repl.SessionInfo;
 import org.apache.ignite.internal.cli.core.repl.registry.MetricRegistry;
+import org.apache.ignite.rest.client.model.MetricSource;
 
 /** Implementation of {@link MetricRegistry}. */
 @Singleton
@@ -35,11 +35,13 @@ public class MetricRegistryImpl implements MetricRegistry, 
AsyncSessionEventList
     @Inject
     private NodeMetricSourceListCall metricSourceListCall;
 
-    private final Set<String> metricSources = ConcurrentHashMap.newKeySet();
+    private LazyObjectRef<Set<String>> metricSourcesRef;
 
     @Override
     public Set<String> metricSources() {
-        return metricSources;
+        return (metricSourcesRef == null || metricSourcesRef.get() == null)
+                ? Set.of()
+                : metricSourcesRef.get();
     }
 
     /**
@@ -49,23 +51,18 @@ public class MetricRegistryImpl implements MetricRegistry, 
AsyncSessionEventList
      */
     @Override
     public void onConnect(SessionInfo sessionInfo) {
-        CompletableFuture.runAsync(() -> {
-            try {
-                //TODO https://issues.apache.org/jira/browse/IGNITE-17416
-                metricSourceListCall.execute(new 
UrlCallInput(sessionInfo.nodeUrl()))
-                        .body()
-                        .forEach(source -> 
metricSources.add(source.getName()));
-            } catch (Exception ignored) {
-                // no-op
-            }
-        });
+        metricSourcesRef = new LazyObjectRef<>(() -> 
fetchMetricSources(sessionInfo));
+    }
+
+    private Set<String> fetchMetricSources(SessionInfo sessionInfo) {
+        return metricSourceListCall.execute(new 
UrlCallInput(sessionInfo.nodeUrl()))
+                .body().stream()
+                .map(MetricSource::getName)
+                .collect(Collectors.toSet());
     }
 
-    /**
-     * Clears metric sources list.
-     */
     @Override
     public void onDisconnect() {
-        metricSources.clear();
+        metricSourcesRef = null;
     }
 }
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/NodeConfigRegistryImpl.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/NodeConfigRegistryImpl.java
index 1f97fb22b1..b50f09790c 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/NodeConfigRegistryImpl.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/NodeConfigRegistryImpl.java
@@ -20,8 +20,6 @@ package 
org.apache.ignite.internal.cli.core.repl.registry.impl;
 import com.typesafe.config.Config;
 import com.typesafe.config.ConfigFactory;
 import jakarta.inject.Singleton;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.atomic.AtomicReference;
 import org.apache.ignite.internal.cli.call.configuration.NodeConfigShowCall;
 import 
org.apache.ignite.internal.cli.call.configuration.NodeConfigShowCallInput;
 import org.apache.ignite.internal.cli.core.repl.AsyncSessionEventListener;
@@ -34,7 +32,7 @@ public class NodeConfigRegistryImpl implements 
NodeConfigRegistry, AsyncSessionE
 
     private final NodeConfigShowCall nodeConfigShowCall;
 
-    private final AtomicReference<Config> config = new AtomicReference<>(null);
+    private LazyObjectRef<Config> configRef;
 
     public NodeConfigRegistryImpl(NodeConfigShowCall nodeConfigShowCall) {
         this.nodeConfigShowCall = nodeConfigShowCall;
@@ -42,28 +40,25 @@ public class NodeConfigRegistryImpl implements 
NodeConfigRegistry, AsyncSessionE
 
     @Override
     public void onConnect(SessionInfo sessionInfo) {
-        CompletableFuture.runAsync(() -> {
-            try {
-                config.set(ConfigFactory.parseString(
-                        nodeConfigShowCall.execute(
-                                // todo 
https://issues.apache.org/jira/browse/IGNITE-17416
-                                
NodeConfigShowCallInput.builder().nodeUrl(sessionInfo.nodeUrl()).build()
-                        ).body().getValue())
-                );
-            } catch (Exception ignored) {
-                // no-op
-            }
-        });
+        configRef = new LazyObjectRef<>(() -> fetchConfig(sessionInfo));
+    }
+
+    private Config fetchConfig(SessionInfo sessionInfo) {
+        return ConfigFactory.parseString(
+                nodeConfigShowCall.execute(
+                        // todo 
https://issues.apache.org/jira/browse/IGNITE-17416
+                        
NodeConfigShowCallInput.builder().nodeUrl(sessionInfo.nodeUrl()).build()
+                ).body().getValue());
     }
 
     @Override
     public void onDisconnect() {
-
+        configRef = null;
     }
 
     /** {@inheritDoc} */
     @Override
     public Config config() {
-        return this.config.get();
+        return configRef == null ? null : configRef.get();
     }
 }
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/NodeNameRegistryImpl.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/NodeNameRegistryImpl.java
index e0de828d6a..a38b3a7193 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/NodeNameRegistryImpl.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/NodeNameRegistryImpl.java
@@ -108,7 +108,7 @@ public class NodeNameRegistryImpl implements 
NodeNameRegistry, AsyncSessionEvent
      */
 
     @Override
-    public void onConnect(SessionInfo sessionInfo) {
+    public synchronized void onConnect(SessionInfo sessionInfo) {
         if (executor == null) {
             executor = Executors.newSingleThreadScheduledExecutor(new 
NamedThreadFactory("NodeNameRegistry", log));
             executor.scheduleWithFixedDelay(() ->
@@ -120,7 +120,7 @@ public class NodeNameRegistryImpl implements 
NodeNameRegistry, AsyncSessionEvent
      * Stops pulling updates.
      */
     @Override
-    public void onDisconnect() {
+    public synchronized void onDisconnect() {
         if (executor != null) {
             shutdownAndAwaitTermination(executor, 3, TimeUnit.SECONDS);
             executor = null;
diff --git 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/UnitsRegistryImpl.java
 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/UnitsRegistryImpl.java
index 8067077112..b72eadf527 100644
--- 
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/UnitsRegistryImpl.java
+++ 
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/core/repl/registry/impl/UnitsRegistryImpl.java
@@ -19,11 +19,10 @@ package 
org.apache.ignite.internal.cli.core.repl.registry.impl;
 
 import jakarta.inject.Singleton;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
 import org.apache.ignite.internal.cli.call.unit.ListUnitCall;
 import org.apache.ignite.internal.cli.call.unit.UnitStatusRecord;
 import org.apache.ignite.internal.cli.core.call.CallOutput;
@@ -40,7 +39,7 @@ public class UnitsRegistryImpl implements UnitsRegistry, 
AsyncSessionEventListen
 
     private final ListUnitCall call;
 
-    private final ConcurrentMap<String, Set<String>> idToVersions = new 
ConcurrentHashMap<>();
+    private LazyObjectRef<Map<String, Set<String>>> idToVersionsRef;
 
     public UnitsRegistryImpl(ListUnitCall call) {
         this.call = call;
@@ -48,34 +47,44 @@ public class UnitsRegistryImpl implements UnitsRegistry, 
AsyncSessionEventListen
 
     @Override
     public void onConnect(SessionInfo sessionInfo) {
-        CompletableFuture.runAsync(() -> updateState(sessionInfo.nodeUrl()));
+        updateState(sessionInfo.nodeUrl());
     }
 
     private void updateState(String url) {
-        try {
-            lastKnownUrl.set(url);
+        lastKnownUrl.set(url);
+
+        idToVersionsRef = new LazyObjectRef<>(() -> {
             CallOutput<List<UnitStatusRecord>> output = call.execute(new 
UrlCallInput(url));
             if (!output.hasError() && !output.isEmpty()) {
-                output.body().forEach(record -> idToVersions.put(record.id(), 
record.versionToDeploymentInfo().keySet()));
+
+                return output.body().stream()
+                        .collect(Collectors.toMap(
+                                UnitStatusRecord::id,
+                                record -> 
record.versionToDeploymentInfo().keySet())
+                        );
+            } else {
+                return null;
             }
-        } catch (Exception ignored) {
-            // no-op
-        }
+        });
     }
 
     @Override
     public void onDisconnect() {
-        idToVersions.clear();
+        idToVersionsRef = null;
     }
 
     @Override
     public Set<String> versions(String unitId) {
-        return idToVersions.get(unitId);
+        return (idToVersionsRef == null || idToVersionsRef.get() == null)
+                ? Set.of()
+                : idToVersionsRef.get().get(unitId);
     }
 
     @Override
     public Set<String> ids() {
-        return idToVersions.keySet();
+        return (idToVersionsRef == null || idToVersionsRef.get() == null)
+                ? Set.of()
+                : idToVersionsRef.get().keySet();
     }
 
     @Override
diff --git 
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/core/repl/registry/impl/LazyObjectRefTest.java
 
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/core/repl/registry/impl/LazyObjectRefTest.java
new file mode 100644
index 0000000000..972f37fa1c
--- /dev/null
+++ 
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/core/repl/registry/impl/LazyObjectRefTest.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.ignite.internal.cli.core.repl.registry.impl;
+
+import static org.awaitility.Awaitility.await;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+
+import java.util.concurrent.CountDownLatch;
+import org.junit.jupiter.api.Test;
+
+class LazyObjectRefTest {
+
+    @Test
+    void returnsOk() {
+        // Given not throwing supplier
+        LazyObjectRef<String> ref = new LazyObjectRef<>(() -> "Hi");
+
+        // Expect returns value from supplier
+        await().untilAsserted(
+                () -> assertThat(ref.get(), equalTo("Hi"))
+        );
+    }
+
+    @Test
+    void returnsOkLazy() {
+        // Given supplier that returns a value only on a second call
+        CountDownLatch latch = new CountDownLatch(1);
+        LazyObjectRef<String> ref = new LazyObjectRef<>(() -> {
+            if (latch.getCount() == 1L) {
+                latch.countDown();
+                throw new RuntimeException();
+            } else {
+                return "Hi from the second attempt";
+            }
+        });
+
+        // When
+        await().untilAsserted(
+                () -> assertThat(ref.get(), equalTo("Hi from the second 
attempt"))
+        );
+        // And the latch is counted down
+        assertThat(latch.getCount(), is(0L));
+    }
+}

Reply via email to