http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/VisorArgListSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/VisorArgListSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/VisorArgListSpec.scala
new file mode 100644
index 0000000..8b71918
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/VisorArgListSpec.scala
@@ -0,0 +1,72 @@
+/*
+ * 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.visor.commands
+
+import org.apache.ignite.visor.visor
+import org.scalatest._
+
+import visor._
+
+/**
+ * Test for visor's argument list parsing.
+ */
+class VisorArgListSpec extends FlatSpec with ShouldMatchers {
+    behavior of "A visor argument list"
+
+    it should "properly parse 'null' arguments" in {
+        val v = parseArgs(null)
+
+        assert(v.isEmpty)
+    }
+
+    it should "properly parse non-empty arguments" in {
+        val v = parseArgs("-a=b c d -minus -d=")
+
+        assert(v.size == 5)
+
+        assert(v(0)._1 == "a")
+        assert(v(0)._2 == "b")
+
+        assert(v(1)._1 == null)
+        assert(v(1)._2 == "c")
+
+        assert(v(2)._1 == null)
+        assert(v(2)._2 == "d")
+
+        assert(v(3)._1 == "minus")
+        assert(v(3)._2 == null)
+
+        assert(v(4)._1 == "d")
+        assert(v(4)._2 == "")
+    }
+
+    it should "properly parse quoted arguments" in {
+        val v = parseArgs("-a='b 'c' d' -minus -d=")
+
+        assert(v.size == 3)
+
+        assert(v(0)._1 == "a")
+        assert(v(0)._2 == "b 'c' d")
+
+        assert(v(1)._1 == "minus")
+        assert(v(1)._2 == null)
+
+        assert(v(2)._1 == "d")
+        assert(v(2)._2 == "")
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/VisorFileNameCompleterSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/VisorFileNameCompleterSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/VisorFileNameCompleterSpec.scala
new file mode 100644
index 0000000..9767fc4
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/VisorFileNameCompleterSpec.scala
@@ -0,0 +1,58 @@
+/*
+ * 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.visor.commands
+
+import org.scalatest._
+
+import java.io.File
+import java.util
+
+/**
+ * Test for visor's file name completer.
+ */
+class VisorFileNameCompleterSpec extends FlatSpec with ShouldMatchers {
+    behavior of "A visor file name completer"
+
+    it should "properly parse empty path" in {
+        val c = new VisorFileNameCompleter()
+
+        val res = new util.ArrayList[CharSequence]()
+
+        c.complete("", 0, res)
+
+        assertResult(new File("").getAbsoluteFile.listFiles().length)(res.size)
+
+        res.clear()
+
+        c.complete(null, 0, res)
+
+        assertResult(new File("").getAbsoluteFile.listFiles().length)(res.size)
+
+        res.clear()
+
+        c.complete("    ", 2, res)
+
+        assertResult(new File("").getAbsoluteFile.listFiles().length)(res.size)
+
+        res.clear()
+
+        c.complete("help ", 5, res)
+
+        assertResult(new File("").getAbsoluteFile.listFiles().length)(res.size)
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/ack/VisorAckCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/ack/VisorAckCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/ack/VisorAckCommandSpec.scala
new file mode 100644
index 0000000..97ccfb7
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/ack/VisorAckCommandSpec.scala
@@ -0,0 +1,41 @@
+/*
+ * 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.visor.commands.ack
+
+import org.apache.ignite.visor.{VisorRuntimeBaseSpec, visor}
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.ack.VisorAckCommand._
+
+/**
+ * Unit test for 'ack' command.
+ */
+class VisorAckCommandSpec extends VisorRuntimeBaseSpec(2) {
+    behavior of "A 'ack' visor command"
+
+    it should "properly execute w/o arguments" in {
+        visor ack()
+    }
+
+    it should "properly execute with arguments" in {
+        visor ack "Broadcasting!"
+    }
+
+    it should "print error message when not connected" in {
+        visor ack()
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommandSpec.scala
new file mode 100644
index 0000000..c919307
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommandSpec.scala
@@ -0,0 +1,155 @@
+/*
+ * 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.visor.commands.alert
+
+import org.apache.ignite.Ignition
+import org.apache.ignite.configuration.IgniteConfiguration
+import org.apache.ignite.spi.discovery.DiscoverySpi
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder
+
+import java.util.regex.Pattern
+
+import org.apache.ignite.visor.{VisorRuntimeBaseSpec, visor}
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.alert.VisorAlertCommand._
+
+/**
+ * Unit test for alert commands.
+ */
+class VisorAlertCommandSpec extends VisorRuntimeBaseSpec(1) {
+    /** */
+    val ipFinder = new TcpDiscoveryVmIpFinder(true)
+
+    /**  */
+    val out = new java.io.ByteArrayOutputStream
+
+    /**
+     * Creates grid configuration for provided grid host.
+     *
+     * @param name Grid name.
+     * @return Grid configuration.
+     */
+    override def config(name: String): IgniteConfiguration = {
+        val cfg = new IgniteConfiguration
+
+        cfg.setGridName(name)
+        cfg.setLifeCycleEmailNotification(false)
+        cfg.setLocalHost("127.0.0.1")
+
+        val discoSpi: TcpDiscoverySpi = new TcpDiscoverySpi()
+
+        discoSpi.setIpFinder(ipFinder)
+
+        cfg.setDiscoverySpi(discoSpi.asInstanceOf[DiscoverySpi])
+
+        cfg
+    }
+
+    override def afterAll() {
+        super.afterAll()
+
+        out.close()
+    }
+
+    /**
+     * Redirect stdout and compare output with specified text.
+     *
+     * @param block Function to execute.
+     * @param text Text to compare with.
+     * @param exp If `true` then stdout must contain `text` otherwise must not.
+     */
+    private[this] def checkOut(block: => Unit, text: String, exp: Boolean = 
true) {
+        try {
+            Console.withOut(out)(block)
+
+            assertResult(exp)(out.toString.contains(text))
+        }
+        finally {
+            out.reset()
+        }
+    }
+
+    /**
+     * Redirect stdout and compare output with specified regexp.
+     *
+     * @param block Function to execute.
+     * @param regex Regexp to match with.
+     */
+    private[this] def matchOut(block: => Unit, regex: String) {
+        try {
+            Console.withOut(out)(block)
+
+            assertResult(true)(Pattern.compile(regex, 
Pattern.MULTILINE).matcher(out.toString).find())
+        }
+        finally {
+            out.reset()
+        }
+    }
+
+    behavior of "An 'alert' visor command"
+
+    it should "print not connected error message" in {
+        visor.close()
+
+        checkOut(visor.alert("-r -t=5 -cc=gte4"), "Visor is disconnected.")
+
+        checkOut(visor.alert(), "No alerts are registered.")
+    }
+
+    it should "register new alert" in {
+        try {
+            checkOut(visor.alert(), "No alerts are registered.")
+
+            matchOut(visor.alert("-r -t=5 -cc=gte4"), "Alert.+registered.")
+
+            checkOut(visor.alert(), "No alerts are registered.", false)
+        }
+        finally {
+            visor.alert("-u -a")
+        }
+    }
+
+    it should "print error messages on incorrect alerts" in {
+        try {
+            matchOut(visor.alert("-r -t=5"), "Alert.+registered.")
+
+            checkOut(visor.alert("-r -UNKNOWN_KEY=lt20"), "Invalid argument")
+
+            checkOut(visor.alert("-r -cc=UNKNOWN_OPERATION20"), "Invalid 
expression")
+        }
+        finally {
+            visor.alert("-u -a")
+        }
+    }
+
+    it should "write alert to log" in {
+        try {
+            matchOut(visor.alert("-r -nc=gte1"), "Alert.+registered.")
+
+            Ignition.start(config("node-2"))
+
+            Ignition.stop("node-2", false)
+
+            checkOut(visor.alert(), "No alerts are registered.", false)
+        }
+        finally {
+            visor.alert("-u -a")
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cache/VisorCacheClearCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cache/VisorCacheClearCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cache/VisorCacheClearCommandSpec.scala
new file mode 100644
index 0000000..660d1e8
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cache/VisorCacheClearCommandSpec.scala
@@ -0,0 +1,116 @@
+/*
+ * 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.visor.commands.cache
+
+import org.apache.ignite.cache.CacheConfiguration
+import org.apache.ignite.cache.{GridCacheMode, GridCacheAtomicityMode}
+import GridCacheAtomicityMode._
+import GridCacheMode._
+import org.apache.ignite.visor.{VisorRuntimeBaseSpec, visor}
+import org.gridgain.grid.cache._
+
+import org.apache.ignite.Ignition
+import org.apache.ignite.configuration.IgniteConfiguration
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder
+import org.jetbrains.annotations.Nullable
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.cache.VisorCacheCommand._
+
+import scala.collection.JavaConversions._
+
+/**
+ *
+ */
+class VisorCacheClearCommandSpec extends VisorRuntimeBaseSpec(2) {
+    /** IP finder. */
+    val ipFinder = new TcpDiscoveryVmIpFinder(true)
+
+    /**
+     * Creates grid configuration for provided grid host.
+     *
+     * @param name Grid name.
+     * @return Grid configuration.
+     */
+    override def config(name: String): IgniteConfiguration = {
+        val cfg = new IgniteConfiguration
+
+        cfg.setGridName(name)
+        cfg.setLocalHost("127.0.0.1")
+        cfg.setCacheConfiguration(cacheConfig(null), cacheConfig("cache"))
+
+        val discoSpi = new TcpDiscoverySpi()
+
+        discoSpi.setIpFinder(ipFinder)
+
+        cfg.setDiscoverySpi(discoSpi)
+
+        cfg
+    }
+
+    /**
+     * @param name Cache name.
+     * @return Cache Configuration.
+     */
+    def cacheConfig(@Nullable name: String): CacheConfiguration = {
+        val cfg = new CacheConfiguration
+
+        cfg.setCacheMode(REPLICATED)
+        cfg.setAtomicityMode(TRANSACTIONAL)
+        cfg.setName(name)
+
+        cfg
+    }
+
+    behavior of "An 'cclear' visor command"
+
+    it should "show correct result for default cache" in {
+        Ignition.ignite("node-1").cache[Int, Int](null).putAll(Map(1 -> 1, 2 
-> 2, 3 -> 3))
+
+        Ignition.ignite("node-1").cache[Int, Int](null).lock(1, 0)
+
+        VisorCacheClearCommand().clear(Nil, None)
+
+        Ignition.ignite("node-1").cache[Int, Int](null).unlock(1)
+
+        VisorCacheClearCommand().clear(Nil, None)
+    }
+
+    it should "show correct result for named cache" in {
+        Ignition.ignite("node-1").cache[Int, Int]("cache").putAll(Map(1 -> 1, 
2 -> 2, 3 -> 3))
+
+        Ignition.ignite("node-1").cache[Int, Int]("cache").lock(1, 0)
+
+        visor.cache("-clear -c=cache")
+
+        Ignition.ignite("node-1").cache[Int, Int]("cache").unlock(1)
+
+        visor.cache("-clear -c=cache")
+    }
+
+    it should "show correct help" in {
+        VisorCacheCommand
+
+        visor.help("cache")
+    }
+
+    it should "show empty projection error message" in {
+        visor.cache("-clear -c=wrong")
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommandSpec.scala
new file mode 100644
index 0000000..d92685e
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommandSpec.scala
@@ -0,0 +1,103 @@
+/*
+ * 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.visor.commands.cache
+
+import org.apache.ignite.Ignition
+import org.apache.ignite.cache.query.GridCacheQuerySqlField
+import org.apache.ignite.visor.visor
+import org.scalatest._
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.cache.VisorCacheCommand._
+
+/**
+ * Unit test for 'events' command.
+ */
+class VisorCacheCommandSpec extends FlatSpec with Matchers with 
BeforeAndAfterAll {
+    /**
+     * Open Visor.
+     */
+    override def beforeAll() {
+        val g = Ignition.start("examples/config/example-cache.xml")
+
+        assert(g.caches().size() > 0)
+
+        visor.open("-d")
+    }
+
+    /**
+     * Close Visor.
+     */
+    override def afterAll() {
+        visor.close()
+
+        Ignition.stop(false)
+    }
+
+    behavior of "A 'cache' visor command"
+
+    it should "put/get some values to/from cache and display information about 
caches" in {
+        val c = Ignition.ignite.cache[String, String]("partitioned")
+
+        for (i <- 0 to 3) {
+            val kv = "" + i
+
+            c.put(kv, kv)
+
+            c.get(kv)
+        }
+
+        visor.cache()
+    }
+
+    it should "run query and display information about caches" in {
+        val g = Ignition.ignite
+
+        val c = g.cache[Int, Foo]("replicated")
+
+        c.put(0, Foo(20))
+        c.put(1, Foo(100))
+        c.put(2, Foo(101))
+        c.put(3, Foo(150))
+
+        // Create two queries
+        val q1 = c.queries().createSqlQuery(classOf[Foo], "_key > ?")
+        c.queries().createSqlQuery(classOf[Foo], "_key = ?")
+
+        // Execute only one query
+        q1.execute(100.asInstanceOf[java.lang.Integer]).get
+
+        visor cache "-a"
+    }
+
+    it should "display correct information for 'replicated' cache only" in {
+        visor cache "-n=replicated -a"
+    }
+
+    it should "display correct information for all caches" in {
+        visor cache "-a"
+    }
+}
+
+/**
+ * Object for queries.
+ */
+private case class Foo(
+    @GridCacheQuerySqlField
+    value: Int
+)

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cache/VisorCacheCompactCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cache/VisorCacheCompactCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cache/VisorCacheCompactCommandSpec.scala
new file mode 100644
index 0000000..d1d565f
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cache/VisorCacheCompactCommandSpec.scala
@@ -0,0 +1,106 @@
+/*
+ * 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.visor.commands.cache
+
+import org.apache.ignite.cache.CacheConfiguration
+import org.apache.ignite.cache.GridCacheMode
+import GridCacheMode._
+import org.apache.ignite.visor.{VisorRuntimeBaseSpec, visor}
+import org.gridgain.grid.cache._
+
+import org.apache.ignite.Ignition
+import org.apache.ignite.configuration.IgniteConfiguration
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder
+import org.jetbrains.annotations.Nullable
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.cache.VisorCacheCommand._
+
+import scala.collection.JavaConversions._
+
+/**
+ *
+ */
+class VisorCacheCompactCommandSpec extends VisorRuntimeBaseSpec(2) {
+    /** IP finder. */
+    val ipFinder = new TcpDiscoveryVmIpFinder(true)
+
+    /**
+     * Creates grid configuration for provided grid host.
+     *
+     * @param name Grid name.
+     * @return Grid configuration.
+     */
+    override def config(name: String): IgniteConfiguration = {
+        val cfg = new IgniteConfiguration
+
+        cfg.setGridName(name)
+        cfg.setLocalHost("127.0.0.1")
+        cfg.setCacheConfiguration(cacheConfig(null), cacheConfig("cache"))
+
+        val discoSpi = new TcpDiscoverySpi()
+
+        discoSpi.setIpFinder(ipFinder)
+
+        cfg.setDiscoverySpi(discoSpi)
+
+        cfg
+    }
+
+    /**
+     * @param name Cache name.
+     * @return Cache Configuration.
+     */
+    def cacheConfig(@Nullable name: String): CacheConfiguration = {
+        val cfg = new CacheConfiguration
+
+        cfg.setCacheMode(REPLICATED)
+        cfg.setName(name)
+
+        cfg
+    }
+
+    behavior of "An 'ccompact' visor command"
+
+    it should "show correct result for default cache" in {
+        Ignition.ignite("node-1").cache[Int, Int](null).putAll(Map(1 -> 1, 2 
-> 2, 3 -> 3))
+
+        Ignition.ignite("node-1").cache[Int, Int](null).clear(1)
+
+        VisorCacheCompactCommand().compact(Nil, None)
+    }
+
+    it should "show correct result for named cache" in {
+        Ignition.ignite("node-1").cache[Int, Int]("cache").putAll(Map(1 -> 1, 
2 -> 2, 3 -> 3))
+
+        Ignition.ignite("node-1").cache[Int, Int]("cache").clear(1)
+
+        visor.cache("-compact -c=cache")
+    }
+
+    it should "show correct help" in {
+        VisorCacheCommand
+
+        visor.help("cache")
+    }
+
+    it should "show empty projection error message" in {
+        visor.cache("-compact -c=wrong")
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommandSpec.scala
new file mode 100644
index 0000000..c0ceb09
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommandSpec.scala
@@ -0,0 +1,52 @@
+/*
+ * 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.visor.commands.config
+
+import org.apache.ignite.configuration.IgniteConfiguration
+import org.apache.ignite.events.IgniteEventType._
+import org.apache.ignite.visor.{VisorRuntimeBaseSpec, visor}
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.config.VisorConfigurationCommand._
+
+/**
+ * Unit test for 'config' command.
+ */
+class VisorConfigurationCommandSpec extends VisorRuntimeBaseSpec(1) {
+    /**
+     * Creates grid configuration for provided grid host.
+     *
+     * @param name Grid name.
+     * @return Grid configuration.
+     */
+    override def config(name: String): IgniteConfiguration = {
+        val cfg = new IgniteConfiguration
+
+        cfg.setGridName(name)
+        cfg.setLifeCycleEmailNotification(false)
+        cfg.setIncludeEventTypes(EVTS_ALL: _*)
+
+        cfg
+    }
+
+    behavior of "A 'config' visor command"
+
+    it should "print configuration for first node" in {
+        visor.config("-id8=@n0")
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cswap/VisorCacheSwapCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cswap/VisorCacheSwapCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cswap/VisorCacheSwapCommandSpec.scala
new file mode 100644
index 0000000..860558b
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/cswap/VisorCacheSwapCommandSpec.scala
@@ -0,0 +1,92 @@
+/*
+ * 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.visor.commands.cswap
+
+import org.apache.ignite.cache.CacheConfiguration
+
+import org.apache.ignite.Ignition
+import org.apache.ignite.cache.GridCacheMode
+import org.apache.ignite.configuration.IgniteConfiguration
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder
+import org.apache.ignite.visor.{VisorRuntimeBaseSpec, visor}
+import org.jetbrains.annotations.Nullable
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.cache.VisorCacheCommand._
+
+import scala.collection.JavaConversions._
+
+class VisorCacheSwapCommandSpec extends VisorRuntimeBaseSpec(2) {
+    /** IP finder. */
+    val ipFinder = new TcpDiscoveryVmIpFinder(true)
+
+    /**
+     * Creates grid configuration for provided grid host.
+     *
+     * @param name Grid name.
+     * @return Grid configuration.
+     */
+    override def config(name: String): IgniteConfiguration = {
+        val cfg = new IgniteConfiguration
+
+        cfg.setGridName(name)
+        cfg.setLocalHost("127.0.0.1")
+        cfg.setCacheConfiguration(cacheConfig(null), cacheConfig("cache"))
+
+        val discoSpi = new TcpDiscoverySpi()
+
+        discoSpi.setIpFinder(ipFinder)
+
+        cfg.setDiscoverySpi(discoSpi)
+
+        cfg
+    }
+
+    /**
+     * @param name Cache name.
+     * @return Cache Configuration.
+     */
+    def cacheConfig(@Nullable name: String): CacheConfiguration = {
+        val cfg = new CacheConfiguration
+
+        cfg.setName(name)
+        cfg.setCacheMode(GridCacheMode.PARTITIONED)
+        cfg.setSwapEnabled(true)
+
+        cfg
+    }
+
+    behavior of "An 'cswap' visor command"
+
+    it should "show correct result for default cache" in {
+        Ignition.ignite("node-1").cache[Int, Int](null).putAll(Map(1 -> 1, 2 
-> 2, 3 -> 3))
+
+        visor.cache("-swap -c=<default>")
+    }
+
+    it should "show correct result for named cache" in {
+        Ignition.ignite("node-1").cache[Int, Int]("cache").putAll(Map(1 -> 1, 
2 -> 2, 3 -> 3))
+
+        visor.cache("-swap -c=cache")
+    }
+
+    it should "show empty projection error message" in {
+        visor.cache("-swap -c=wrong")
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommandSpec.scala
new file mode 100644
index 0000000..e568800
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommandSpec.scala
@@ -0,0 +1,35 @@
+/*
+ * 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.visor.commands.deploy
+
+import org.apache.ignite.visor.visor
+import org.scalatest._
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.deploy.VisorDeployCommand._
+
+/**
+ * Unit test for 'deploy' command.
+ */
+class VisorDeployCommandSpec extends FlatSpec with Matchers {
+    behavior of "A 'deploy' visor command"
+
+    it should "copy folder" in {
+        visor.deploy("-h=uname:passwd@localhost -s=/home/uname/test -d=dir")
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/disco/VisorDiscoveryCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/disco/VisorDiscoveryCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/disco/VisorDiscoveryCommandSpec.scala
new file mode 100644
index 0000000..e93650c
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/disco/VisorDiscoveryCommandSpec.scala
@@ -0,0 +1,87 @@
+/*
+ * 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.visor.commands.disco
+
+import org.apache.ignite.Ignition
+import org.apache.ignite.configuration.IgniteConfiguration
+import org.apache.ignite.visor.{VisorRuntimeBaseSpec, visor}
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.disco.VisorDiscoveryCommand._
+
+/**
+ * Unit test for 'disco' command.
+ */
+class VisorDiscoveryCommandSpec extends VisorRuntimeBaseSpec(4) {
+    /**
+     * Open visor and execute several tasks before all tests.
+     */
+    override protected def beforeAll() {
+        super.beforeAll()
+
+        Ignition.stop("node-1", false)
+        Ignition.stop("node-2", false)
+    }
+
+    /**
+     * Creates grid configuration for provided grid host.
+     *
+     * @param name Grid name.
+     * @return Grid configuration.
+     */
+    override def config(name: String): IgniteConfiguration = {
+        val cfg = new IgniteConfiguration
+
+        cfg.setGridName(name)
+        cfg.setLifeCycleEmailNotification(false)
+
+        cfg
+    }
+
+    behavior of  "A 'disco' visor command"
+
+    it should "advise to connect" in  {
+        closeVisorQuiet()
+
+        visor.disco()
+    }
+
+    it should "show all discovery events" in  {
+        visor.disco()
+    }
+
+    it should "show all discovery events in reversed order" in  {
+        visor.disco("-r")
+    }
+
+    it should "show discovery events from last two minutes" in {
+        visor.disco("-t=2m")
+    }
+
+    it should "show discovery events from last two minutes in reversed order " 
in {
+        visor.disco("-t=2m -r")
+    }
+
+    it should "show top 3 discovery events" in  {
+        visor.disco("-c=3")
+    }
+
+    it should "print error message with invalid count" in {
+        visor.disco("-c=x")
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/events/VisorEventsCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/events/VisorEventsCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/events/VisorEventsCommandSpec.scala
new file mode 100644
index 0000000..ea19949
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/events/VisorEventsCommandSpec.scala
@@ -0,0 +1,64 @@
+/*
+ * 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.visor.commands.events
+
+import org.apache.ignite.configuration.IgniteConfiguration
+import org.apache.ignite.visor.{VisorRuntimeBaseSpec, visor}
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.events.VisorEventsCommand._
+
+/**
+ * Unit test for 'events' command.
+ */
+class VisorEventsCommandSpec extends VisorRuntimeBaseSpec(1) {
+    /**
+     * Creates grid configuration for provided grid host.
+     *
+     * @param name Grid name.
+     * @return Grid configuration.
+     */
+    override def config(name: String): IgniteConfiguration = {
+        val cfg = new IgniteConfiguration
+
+        cfg.setGridName(name)
+        cfg.setLifeCycleEmailNotification(false)
+
+        cfg
+    }
+
+    behavior of "A 'events' visor command"
+
+    it should "print error message when not connected" in {
+        closeVisorQuiet()
+
+        visor.events()
+    }
+
+    it should "display all events from remote node" in {
+        visor.events("-id8=@n0")
+    }
+
+    it should "display top 3 events from remote node" in {
+        visor.events("-id8=@n0 -c=3")
+    }
+
+    it should "print error message with invalid count" in {
+        visor.events("-id8=@n0 -c=x")
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/gc/VisorGcCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/gc/VisorGcCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/gc/VisorGcCommandSpec.scala
new file mode 100644
index 0000000..e6c3492
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/gc/VisorGcCommandSpec.scala
@@ -0,0 +1,58 @@
+/*
+ * 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.visor.commands.gc
+
+import org.apache.ignite.visor.visor
+import org.scalatest._
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.gc.VisorGcCommand._
+import org.apache.ignite.visor.commands.top.VisorTopologyCommand._
+
+/**
+ * Unit test for 'gc' command.
+ */
+class VisorGcCommandSpec extends FlatSpec with Matchers with BeforeAndAfterAll 
{
+    behavior of "A 'gc' visor command"
+
+    override def beforeAll() {
+        visor.open("-d")
+
+        visor.top()
+    }
+
+    override def afterAll() {
+        visor.close()
+    }
+
+    it should "run GC on all nodes" in {
+        visor.gc()
+    }
+
+    it should "run GC on first node" in {
+        visor.gc("-id8=@n0")
+    }
+
+    it should "run GC and DGC on all nodes" in {
+        visor.gc("-c")
+    }
+
+    it should "run GC and DGC on first node" in {
+        visor.gc("-id8=@n0 -c")
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/help/VisorHelpCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/help/VisorHelpCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/help/VisorHelpCommandSpec.scala
new file mode 100644
index 0000000..5fca43a
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/help/VisorHelpCommandSpec.scala
@@ -0,0 +1,70 @@
+/*
+ * 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.visor.commands.help
+
+import org.apache.ignite.visor.visor
+import org.scalatest._
+
+import org.gridgain.visor._
+
+/**
+ * Unit test for 'help' command.
+ */
+class VisorHelpCommandSpec extends FlatSpec with Matchers {
+    // Pre-initialize command so that help can be registered.
+    commands.ack.VisorAckCommand
+    commands.ping.VisorPingCommand
+    commands.alert.VisorAlertCommand
+    commands.config.VisorConfigurationCommand
+    commands.top.VisorTopologyCommand
+    commands.kill.VisorKillCommand
+    commands.vvm.VisorVvmCommand
+    commands.node.VisorNodeCommand
+    commands.events.VisorEventsCommand
+    commands.disco.VisorDiscoveryCommand
+    commands.cache.VisorCacheCommand
+    commands.start.VisorStartCommand
+    commands.deploy.VisorDeployCommand
+    commands.start.VisorStartCommand
+
+    "General help" should "properly execute via alias" in { visor.help() }
+    "General help" should "properly execute w/o alias" in { visor.help() }
+    "Help for 'start' command" should "properly execute" in { 
visor.help("start") }
+    "Help for 'deploy' command" should "properly execute" in { 
visor.help("deploy") }
+    "Help for 'events' command" should "properly execute" in { 
visor.help("events") }
+    "Help for 'mclear' command" should "properly execute" in { 
visor.help("mclear") }
+    "Help for 'cache' command" should "properly execute" in { 
visor.help("cache") }
+    "Help for 'disco' command" should "properly execute" in { 
visor.help("disco") }
+    "Help for 'alert' command" should "properly execute" in { 
visor.help("alert") }
+    "Help for 'node' command" should "properly execute" in { 
visor.help("node") }
+    "Help for 'vvm' command" should "properly execute" in { visor.help("vvm") }
+    "Help for 'kill' command" should "properly execute" in { 
visor.help("kill") }
+    "Help for 'top' command" should "properly execute" in { visor.help("top") }
+    "Help for 'config' command" should "properly execute" in { 
visor.help("config") }
+    "Help for 'ack' command" should "properly execute" in { visor.help("ack") }
+    "Help for 'ping' command" should "properly execute" in { 
visor.help("ping") }
+    "Help for 'close' command" should "properly execute" in { 
visor.help("close") }
+    "Help for 'open' command" should "properly execute" in { 
visor.help("open") }
+    "Help for 'status' command" should "properly execute" in { 
visor.help("status") }
+    "Help for 'mset' command" should "properly execute" in { 
visor.help("mset") }
+    "Help for 'mget' command" should "properly execute" in { 
visor.help("mget") }
+    "Help for 'mlist' command" should "properly execute" in { 
visor.help("mlist") }
+    "Help for 'help' command" should "properly execute" in { 
visor.help("help") }
+    "Help for 'log' command" should "properly execute" in { visor.help("log") }
+    "Help for 'dash' command" should "properly execute" in { 
visor.help("dash") }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/kill/VisorKillCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/kill/VisorKillCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/kill/VisorKillCommandSpec.scala
new file mode 100644
index 0000000..36b1de4
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/kill/VisorKillCommandSpec.scala
@@ -0,0 +1,59 @@
+/*
+ * 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.visor.commands.kill
+
+import org.apache.ignite.visor.visor
+import org.scalatest._
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.kill.VisorKillCommand._
+
+/**
+ * Unit test for 'kill' command.
+ */
+class VisorKillCommandSpec extends FlatSpec with Matchers {
+    behavior of "A 'kill' visor command"
+
+    it should "print error message with null argument" in {
+        visor.open("-d")
+        visor.kill(null)
+        visor.close()
+    }
+
+    it should "print error message if both kill and restart specified" in {
+        visor.open("-d")
+        visor.kill("-k -r")
+        visor.close()
+    }
+
+    it should "print error message if not connected" in {
+        visor.kill("-k")
+    }
+
+    it should "restart node" in {
+        visor.open("-d")
+        visor.kill("-r -id8=@n1")
+        visor.close()
+    }
+
+    it should "print error message" in {
+        visor.open("-d")
+        visor.kill("-r -id=xxx")
+        visor.close()
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/log/VisorLogCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/log/VisorLogCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/log/VisorLogCommandSpec.scala
new file mode 100644
index 0000000..afd807a
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/log/VisorLogCommandSpec.scala
@@ -0,0 +1,34 @@
+/*
+ * 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.visor.commands.log
+
+import org.apache.ignite.visor.visor
+import org.scalatest._
+
+import org.gridgain.visor._
+
+/**
+* Unit test for 'log' command.
+*/
+class VisorLogCommandSpec extends FlatSpec with Matchers {
+    behavior of "A 'log' visor command"
+
+    it should "print log status" in {
+        visor.log()
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/mem/VisorMemoryCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/mem/VisorMemoryCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/mem/VisorMemoryCommandSpec.scala
new file mode 100644
index 0000000..02ca041
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/mem/VisorMemoryCommandSpec.scala
@@ -0,0 +1,77 @@
+/*
+ * 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.visor.commands.mem
+
+import org.apache.ignite.visor.visor
+import org.scalatest._
+
+import org.gridgain.visor._
+
+/**
+ * Unit test for memory commands.
+ */
+class VisorMemoryCommandSpec extends FlatSpec with Matchers {
+    "A 'mget' visor command" should "get correct value" in {
+        visor.mset("key", "value")
+
+        assertResult(Option("value"))(visor.mgetOpt("key"))
+
+        visor.mclear()
+    }
+
+    "A 'mlist' visor command" should "list all variables" in {
+        visor.mset("key1", "value1")
+        visor.mset("key2", "value2")
+        visor.mset("key3", "value3")
+
+        visor.mlist()
+        visor.mclear()
+    }
+
+    "A 'mlist' visor command" should "list ax and cx variables" in {
+        visor.mset("a1", "1")
+        visor.mset("a2", "2")
+        visor.mset("b1", "3")
+        visor.mset("b2", "4")
+        visor.mset("c1", "5")
+        visor.mset("c2", "6")
+
+        visor.mlist("ac")
+        visor.mclear()
+    }
+
+    "A 'mclear' visor command" should "remove first two variables" in {
+        visor.mset("key1", "value1")
+        visor.mset("key2", "value2")
+        visor.mset("key3", "value3")
+
+        visor mclear "key1 key2"
+
+        visor.mlist()
+        visor.mclear()
+    }
+
+    "A 'mclear' visor command" should "remove all variables" in {
+        visor.mset("key1", "value1")
+        visor.mset("key2", "value2")
+        visor.mset("key3", "value3")
+
+        visor.mclear()
+        visor.mlist()
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/node/VisorNodeCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/node/VisorNodeCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/node/VisorNodeCommandSpec.scala
new file mode 100644
index 0000000..b434cec
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/node/VisorNodeCommandSpec.scala
@@ -0,0 +1,43 @@
+/*
+ * 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.visor.commands.node
+
+import org.apache.ignite.visor.{VisorRuntimeBaseSpec, visor}
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.node.VisorNodeCommand._
+
+/**
+ * Unit test for 'node' command.
+ */
+class VisorNodeCommandSpec extends VisorRuntimeBaseSpec(1) {
+    behavior of "A 'node' visor command"
+
+    it should "properly execute with valid node ID" in {
+        visor.node("-id8=@n1")
+    }
+
+    it should "print the error message for invalid node ID" in {
+        visor.node("-id8=zeee")
+    }
+
+    it should "print error message when not connected" in {
+        closeVisorQuiet()
+
+        visor.node("") // Arguments are ignored.
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/open/VisorOpenCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/open/VisorOpenCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/open/VisorOpenCommandSpec.scala
new file mode 100644
index 0000000..0f5bb4a
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/open/VisorOpenCommandSpec.scala
@@ -0,0 +1,42 @@
+/*
+ * 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.visor.commands.open
+
+import org.apache.ignite.IgniteCheckedException
+import org.apache.ignite.visor.{VisorRuntimeBaseSpec, visor}
+
+import org.gridgain.visor._
+
+/**
+ * Unit test for 'open' command.
+ */
+class VisorOpenCommandSpec extends VisorRuntimeBaseSpec(3) {
+    behavior of "A 'open' visor command"
+
+    it should "properly connect using default configuration" in {
+        visor.mlist()
+    }
+
+    it should "print error message when already connected" in {
+        try
+            openVisor()
+        catch {
+            case ignored: IgniteCheckedException =>
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/ping/VisorPingCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/ping/VisorPingCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/ping/VisorPingCommandSpec.scala
new file mode 100644
index 0000000..b54a96f
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/ping/VisorPingCommandSpec.scala
@@ -0,0 +1,39 @@
+/*
+ * 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.visor.commands.ping
+
+import org.apache.ignite.visor.{VisorRuntimeBaseSpec, visor}
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.ping.VisorPingCommand._
+
+/**
+ * Unit test for 'ping' command.
+ */
+class VisorPingCommandSpec extends VisorRuntimeBaseSpec(2) {
+    behavior of "A 'ping' visor command"
+
+    it should "properly execute" in {
+        visor.ping()
+    }
+
+    it should "print error message when not connected" in {
+        closeVisorQuiet()
+
+        visor.ping()
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/start/VisorStartCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/start/VisorStartCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/start/VisorStartCommandSpec.scala
new file mode 100644
index 0000000..7611a31
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/start/VisorStartCommandSpec.scala
@@ -0,0 +1,124 @@
+/*
+ * 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.visor.commands.start
+
+import org.apache.ignite.visor.visor
+import org.scalatest._
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.start.VisorStartCommand._
+import org.apache.ignite.visor.commands.top.VisorTopologyCommand._
+
+/**
+ * Unit test for 'start' command.
+ */
+class VisorStartCommandSpec extends FlatSpec with Matchers with 
BeforeAndAfterAll {
+    override def beforeAll() {
+        visor.open("-d")
+    }
+
+    override def afterAll() {
+        visor.close()
+    }
+
+    behavior of "A 'start' visor command"
+
+    it should "should start one new node" in {
+        visor.start("-h=192.168.1.103 -r -p=password")
+    }
+
+    it should "should start two nodes" in {
+        visor.start("-h=uname:passwd@localhost -n=2")
+    }
+
+    it should "print error message with invalid port number" in {
+        visor.start("-h=localhost:x -p=passwd")
+    }
+
+    it should "print error message with zero port number" in {
+        visor.start("-h=localhost:0 -p=passwd")
+    }
+
+    it should "print error message with negative port number" in {
+        visor.start("-h=localhost:-1 -p=passwd")
+    }
+
+    it should "print error message with invalid nodes count" in {
+        visor.start("-h=localhost#x -p=passwd")
+    }
+
+    it should "print error message with zero nodes count" in {
+        visor.start("-h=localhost#0 -p=passwd")
+    }
+
+    it should "print error message with negative nodes count" in {
+        visor.start("-h=localhost#-1 -p=passwd")
+    }
+
+    it should "print error message with incorrect host" in {
+        visor.start("-h=incorrect -p=passwd")
+    }
+
+    it should "print error message with incorrect username" in {
+        visor.start("-h=incorrect@localhost -p=passwd")
+    }
+
+    it should "print error message with incorrect password" in {
+        visor.start("-h=uname:incorrect@localhost")
+    }
+
+    it should "print error message with nonexistent script path" in {
+        visor.start("-h=uname:passwd@localhost -s=incorrect")
+    }
+
+    it should "print error message with incorrect script path" in {
+        visor.start("-h=uname:passwd@localhost -s=bin/readme.txt")
+    }
+
+    it should "print error message with nonexistent config path" in {
+        visor.start("-h=uname:passwd@localhost -c=incorrect")
+    }
+
+    it should "print error message with incorrect config path" in {
+        visor.start("-h=uname:passwd@localhost -c=bin/readme.txt")
+    }
+
+    it should "start one node" in {
+        visor.start("-h=uname:passwd@localhost")
+
+        visor.top()
+    }
+
+    it should "start one node on host identified by IP" in {
+        visor.start("-h=uname:passwd@127.0.0.1")
+
+        visor.top()
+    }
+
+    it should "start two nodes" in {
+        visor.start("-h=uname:passwd@localhost#2")
+
+        visor.top()
+    }
+
+    it should "restart 4 nodes" in {
+        visor.start("-h=uname:passwd@localhost#4 -r")
+
+        visor.top()
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/tasks/VisorTasksCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/tasks/VisorTasksCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/tasks/VisorTasksCommandSpec.scala
new file mode 100644
index 0000000..c048bd3
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/tasks/VisorTasksCommandSpec.scala
@@ -0,0 +1,232 @@
+/*
+ * 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.visor.commands.tasks
+
+import org.apache.ignite.Ignition
+import org.apache.ignite.compute.{ComputeJob, ComputeJobAdapter, 
ComputeJobResult, ComputeTaskSplitAdapter}
+import org.apache.ignite.configuration.IgniteConfiguration
+import org.apache.ignite.events.IgniteEventType
+import org.apache.ignite.events.IgniteEventType._
+import org.apache.ignite.visor.visor
+import org.scalatest._
+
+import java.util
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.tasks.VisorTasksCommand._
+
+import scala.collection.JavaConversions._
+import scala.collection._
+
+/**
+ * Unit test for 'tasks' command.
+ */
+class VisorTasksCommandSpec extends FlatSpec with Matchers with 
BeforeAndAfterAll {
+    /**
+     * Open visor and execute several tasks before all tests.
+     */
+    override def beforeAll() {
+        Ignition.start(config("grid-1"))
+        Ignition.start(config("grid-2"))
+
+        visor.open(config("grid-visor"), "n/a")
+
+        try {
+            val compute = visor.grid.compute().enableAsync
+
+            compute.withName("TestTask1").execute(new TestTask1(), null)
+
+            val fut1 = compute.future()
+
+            compute.withName("TestTask1").execute(new TestTask1(), null)
+
+            val fut2 = compute.future()
+
+            compute.withName("TestTask1").execute(new TestTask1(), null)
+
+            val fut3 = compute.future()
+
+            compute.withName("TestTask2").execute(new TestTask2(), null)
+
+            val fut4 = compute.future()
+
+            compute.withName("Test3").execute(new Test3(), null)
+
+            val fut5 = compute.future()
+
+            fut1.get
+            fut2.get
+            fut3.get
+            fut4.get
+            fut5.get
+        }
+        catch {
+            case _: Exception =>
+        }
+    }
+
+    /**
+     * Creates grid configuration for provided grid host.
+     *
+     * @param name Grid name.
+     * @return Grid configuration.
+     */
+    private def config(name: String): IgniteConfiguration = {
+        val cfg = new IgniteConfiguration
+
+        cfg.setGridName(name)
+        cfg.setLifeCycleEmailNotification(false)
+        cfg.setIncludeEventTypes(EVTS_ALL: _*)
+
+        cfg
+    }
+
+    /**
+     * Close visor after all tests.
+     */
+    override def afterAll() {
+        visor.close()
+
+        Ignition.stopAll(false)
+    }
+
+    behavior of "A 'tasks' visor command"
+
+    it should "print tasks when called w/o arguments" in {
+        visor.tasks()
+    }
+
+    it should "print error message with incorrect argument" in {
+        visor.tasks("-xx")
+    }
+
+    it should "print task summary when called for specific task" in {
+        visor.tasks("-n=@t1")
+    }
+
+    it should "print execution when called for specific execution" in {
+        visor.tasks("-e=@e1")
+    }
+
+    it should "print all tasks" in {
+        visor.tasks("-l")
+    }
+
+    it should "print all tasks and executions" in {
+        visor.tasks("-l -a")
+    }
+
+    it should "print tasks that started during last 5 seconds" in {
+        visor.tasks("-l -t=5s")
+    }
+
+    it should "print error message about invalid time period" in {
+        visor.tasks("-l -t=x2s")
+    }
+
+    it should "print error message about negative time period" in {
+        visor.tasks("-l -t=-10s")
+    }
+
+    it should "print error message about invalid time period specification" in 
{
+        visor.tasks("-l -t=10x")
+    }
+
+    it should "print task summary for the first task" in {
+        visor.tasks("-n=TestTask1")
+    }
+
+    it should "print task summary and executions for the first task" in {
+        visor.tasks("-n=TestTask1 -a")
+    }
+
+    it should "print list of tasks grouped by nodes" in {
+        visor.tasks("-g")
+    }
+
+    it should "print list of tasks that started during last 5 minutes grouped 
by nodes" in {
+        visor.tasks("-g -t=5m")
+    }
+
+    it should "print list of tasks grouped by hosts" in {
+        visor.tasks("-h")
+    }
+
+    it should "print list of tasks that started during last 5 minutes grouped 
by hosts" in {
+        visor.tasks("-h -t=5m")
+    }
+
+    it should "print list of tasks filtered by substring" in {
+        visor.tasks("-s=TestTask")
+    }
+
+    it should "print list of tasks and executions filtered by substring" in {
+        visor.tasks("-s=TestTask -a")
+    }
+}
+
+/**
+ * Test task 1.
+ */
+private class TestTask1 extends ComputeTaskSplitAdapter[String, Void] {
+    def split(gridSize: Int, arg: String): java.util.Collection[_ <: 
ComputeJob] = {
+        Iterable.fill(gridSize)(new ComputeJobAdapter() {
+            def execute() = {
+                println("Task 1")
+
+                null
+            }
+        })
+    }
+
+    def reduce(results: util.List[ComputeJobResult]) = null
+}
+
+/**
+ * Test task 2.
+ */
+private class TestTask2 extends ComputeTaskSplitAdapter[String, Void] {
+    def split(gridSize: Int, arg: String): java.util.Collection[_ <: 
ComputeJob] = {
+        Iterable.fill(gridSize)(new ComputeJobAdapter() {
+            def execute() = {
+                println("Task 2")
+
+                null
+            }
+        })
+    }
+
+    def reduce(results: util.List[ComputeJobResult]) = null
+}
+
+/**
+ * Test task 3 (w/o 'Task' in host for testing '-s' option).
+ */
+private class Test3 extends ComputeTaskSplitAdapter[String, Void] {
+    def split(gridSize: Int, arg: String): java.util.Collection[_ <: 
ComputeJob] = {
+        Iterable.fill(gridSize)(new ComputeJobAdapter() {
+            def execute() = {
+                println("Task 3")
+
+                null
+            }
+        })
+    }
+
+    def reduce(results: util.List[ComputeJobResult]) = null
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/top/VisorTopologyCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/top/VisorTopologyCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/top/VisorTopologyCommandSpec.scala
new file mode 100644
index 0000000..05a0d47
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/top/VisorTopologyCommandSpec.scala
@@ -0,0 +1,63 @@
+/*
+ * 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.visor.commands.top
+
+import org.apache.ignite.visor.{VisorRuntimeBaseSpec, visor}
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.top.VisorTopologyCommand._
+
+/**
+ * Unit test for topology commands.
+ */
+class VisorTopologyCommandSpec extends VisorRuntimeBaseSpec(2) {
+    behavior of "A 'top' visor command"
+
+    it should "advise to connect" in {
+        closeVisorQuiet()
+
+        visor.top()
+    }
+
+    it should "print error message" in {
+        visor.top("-cc=eq1x")
+    }
+
+    it should "print full topology" in {
+        visor.top()
+    }
+
+    it should "print nodes with idle time greater than 12000ms" in {
+        visor.top("-it=gt12000")
+    }
+
+    it should "print nodes with idle time greater than 12sec" in {
+        visor.top("-it=gt12s")
+    }
+
+    it should "print full information about all nodes" in {
+        visor.top("-a")
+    }
+
+    it should "print information about nodes on localhost" in {
+        visor.top("-h=192.168.1.100")
+    }
+
+    it should "print full information about nodes on localhost" in {
+        visor.top("-h=localhost")
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/vvm/VisorVvmCommandSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/vvm/VisorVvmCommandSpec.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/vvm/VisorVvmCommandSpec.scala
new file mode 100644
index 0000000..b1a2877
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/commands/vvm/VisorVvmCommandSpec.scala
@@ -0,0 +1,47 @@
+/*
+ * 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.visor.commands.vvm
+
+import org.apache.ignite.visor.visor
+import org.scalatest._
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.vvm.VisorVvmCommand._
+
+/**
+ * Unit test for 'vvm' command.
+ */
+class VisorVvmCommandSpec extends FlatSpec with Matchers {
+    behavior of "A 'vvm' visor command"
+
+    it should "print error message when not connected" in {
+        visor.vvm()
+    }
+
+    it should "open VisualVM connected to all nodes skipping ones with 
disabled JMX" in {
+        visor.open("-d")
+        visor.vvm()
+        visor.close()
+    }
+
+    it should "open VisualVM connected to first node if it has JMX enabled" in 
{
+        visor.open("-d")
+        visor.vvm("-id8=@n1")
+        visor.close()
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/apache/ignite/visor/testsuites/VisorConsoleSelfTestSuite.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/apache/ignite/visor/testsuites/VisorConsoleSelfTestSuite.scala
 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/testsuites/VisorConsoleSelfTestSuite.scala
new file mode 100644
index 0000000..742e3a1
--- /dev/null
+++ 
b/modules/visor-console/src/test/scala/org/apache/ignite/visor/testsuites/VisorConsoleSelfTestSuite.scala
@@ -0,0 +1,95 @@
+/*
+ * 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.visor.testsuites
+
+import java.net.{InetAddress, UnknownHostException}
+
+import org.apache.ignite.IgniteSystemProperties._
+import org.apache.ignite.visor.VisorTextTableSpec
+import org.apache.ignite.visor.commands.VisorArgListSpec
+import org.apache.ignite.visor.commands.ack.VisorAckCommandSpec
+import org.apache.ignite.visor.commands.alert.VisorAlertCommandSpec
+import org.apache.ignite.visor.commands.cache.{VisorCacheClearCommandSpec, 
VisorCacheCommandSpec, VisorCacheCompactCommandSpec}
+import org.apache.ignite.visor.commands.config.VisorConfigurationCommandSpec
+import org.apache.ignite.visor.commands.cswap.VisorCacheSwapCommandSpec
+import org.apache.ignite.visor.commands.deploy.VisorDeployCommandSpec
+import org.apache.ignite.visor.commands.disco.VisorDiscoveryCommandSpec
+import org.apache.ignite.visor.commands.events.VisorEventsCommandSpec
+import org.apache.ignite.visor.commands.gc.VisorGcCommandSpec
+import org.apache.ignite.visor.commands.help.VisorHelpCommandSpec
+import org.apache.ignite.visor.commands.kill.VisorKillCommandSpec
+import org.apache.ignite.visor.commands.log.VisorLogCommandSpec
+import org.apache.ignite.visor.commands.mem.VisorMemoryCommandSpec
+import org.apache.ignite.visor.commands.node.VisorNodeCommandSpec
+import org.apache.ignite.visor.commands.open.VisorOpenCommandSpec
+import org.apache.ignite.visor.commands.ping.VisorPingCommandSpec
+import org.apache.ignite.visor.commands.start.VisorStartCommandSpec
+import org.apache.ignite.visor.commands.tasks.VisorTasksCommandSpec
+import org.apache.ignite.visor.commands.top.VisorTopologyCommandSpec
+import org.junit.runner.RunWith
+import org.scalatest.Suites
+import org.scalatest.junit.JUnitRunner
+
+/**
+ *
+ */
+@RunWith(classOf[JUnitRunner])
+class VisorConsoleSelfTestSuite extends Suites (
+    new VisorTextTableSpec,
+    new VisorAckCommandSpec,
+    new VisorAlertCommandSpec,
+    new VisorCacheCommandSpec,
+    new VisorCacheClearCommandSpec,
+    new VisorCacheCompactCommandSpec,
+    new VisorConfigurationCommandSpec,
+    new VisorCacheSwapCommandSpec,
+    new VisorDeployCommandSpec,
+    new VisorDiscoveryCommandSpec,
+    new VisorEventsCommandSpec,
+    new VisorGcCommandSpec,
+    new VisorHelpCommandSpec,
+    new VisorKillCommandSpec,
+    new VisorLogCommandSpec,
+    new VisorMemoryCommandSpec,
+    new VisorNodeCommandSpec,
+    new VisorOpenCommandSpec,
+    new VisorPingCommandSpec,
+    new VisorStartCommandSpec,
+    new VisorTasksCommandSpec,
+    new VisorTopologyCommandSpec,
+    new VisorArgListSpec
+) {
+    // Mimic GridTestUtils.getNextMulticastGroup behavior because it can't be 
imported here
+    // as it will create a circular module dependency. Use the highest address.
+    try {
+        val locHost = InetAddress.getLocalHost
+
+        if (locHost != null) {
+            var thirdByte: Int = locHost.getAddress()(3)
+
+            if (thirdByte < 0)
+                thirdByte += 256
+
+            System.setProperty(GG_OVERRIDE_MCAST_GRP, "229." + thirdByte + 
".255.255")
+        }
+    }
+    catch {
+        case e: UnknownHostException =>
+            assert(false, "Unable to get local address.")
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/gridgain/visor/VisorRuntimeBaseSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/gridgain/visor/VisorRuntimeBaseSpec.scala
 
b/modules/visor-console/src/test/scala/org/gridgain/visor/VisorRuntimeBaseSpec.scala
deleted file mode 100644
index e3bd5f0..0000000
--- 
a/modules/visor-console/src/test/scala/org/gridgain/visor/VisorRuntimeBaseSpec.scala
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.gridgain.visor
-
-import org.apache.ignite.Ignition
-import org.apache.ignite.configuration.IgniteConfiguration
-import org.scalatest._
-
-/**
- * Base abstract class for unit tests requiring Visor runtime.
- */
-abstract class VisorRuntimeBaseSpec(private[this] val num: Int) extends 
FlatSpec with Matchers
-    with BeforeAndAfterAll with BeforeAndAfterEach {
-    assert(num >= 1)
-
-    /**
-     * Gets grid configuration.
-     *
-     * @param name Grid name.
-     * @return Grid configuration.
-     */
-    protected def config(name: String): IgniteConfiguration = {
-        val cfg = new IgniteConfiguration
-
-        cfg.setGridName(name)
-
-        cfg
-    }
-
-    protected def openVisor() {
-        visor.open(config("visor-demo-node"), "n/a")
-    }
-
-    protected def closeVisorQuiet() {
-        if (visor.isConnected)
-            visor.close()
-    }
-
-    /**
-     * Runs before all tests.
-     */
-    override protected def beforeAll() {
-        (1 to num).foreach((n: Int) => Ignition.start(config("node-" + n)))
-    }
-
-    /**
-     * Runs after all tests.
-     */
-    override def afterAll() {
-        (1 to num).foreach((n: Int) => Ignition.stop("node-" + n, false))
-    }
-
-    override protected def beforeEach() {
-        openVisor()
-    }
-
-    override protected def afterEach() {
-        closeVisorQuiet()
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/gridgain/visor/VisorTextTableSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/gridgain/visor/VisorTextTableSpec.scala
 
b/modules/visor-console/src/test/scala/org/gridgain/visor/VisorTextTableSpec.scala
deleted file mode 100644
index 7bb149e..0000000
--- 
a/modules/visor-console/src/test/scala/org/gridgain/visor/VisorTextTableSpec.scala
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.gridgain.visor
-
-import org.scalatest._
-
-import org.gridgain.visor.commands.VisorTextTable
-
-import scala.collection._
-
-/**
- * Test for visor text table.
- */
-class VisorTextTableSpec extends FlatSpec with ShouldMatchers {
-    "A table with header" should "render" in {
-        val t = new VisorTextTable()
-
-        t.margin(5, 5, 5, 5)
-
-        t.maxCellWidth = 10
-
-        t.headerStyle("leftPad: 10, rightPad: 5")
-        t #= ("Header 1", mutable.Seq("Header 2.1", "Header 2.2"), "Header 3")
-        t += ("Row 1", mutable.ListBuffer("Row 2"), immutable.List("Row 3.1", 
"Row 3.2"))
-        t += ("1234567890zxcvbnmasdASDFGHJKLQ", mutable.ListBuffer("Row 2"), 
immutable.List("Row 3.1", "Row 3.2"))
-        t += (immutable.Seq("Row 31.1", "Row 31.2"), "Row 11", "Row 21")
-
-        t.render()
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/test/scala/org/gridgain/visor/commands/VisorArgListSpec.scala
----------------------------------------------------------------------
diff --git 
a/modules/visor-console/src/test/scala/org/gridgain/visor/commands/VisorArgListSpec.scala
 
b/modules/visor-console/src/test/scala/org/gridgain/visor/commands/VisorArgListSpec.scala
deleted file mode 100644
index 267ae82..0000000
--- 
a/modules/visor-console/src/test/scala/org/gridgain/visor/commands/VisorArgListSpec.scala
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.gridgain.visor.commands
-
-import org.scalatest._
-
-import org.gridgain.visor.visor._
-
-/**
- * Test for visor's argument list parsing.
- */
-class VisorArgListSpec extends FlatSpec with ShouldMatchers {
-    behavior of "A visor argument list"
-
-    it should "properly parse 'null' arguments" in {
-        val v = parseArgs(null)
-
-        assert(v.isEmpty)
-    }
-
-    it should "properly parse non-empty arguments" in {
-        val v = parseArgs("-a=b c d -minus -d=")
-
-        assert(v.size == 5)
-
-        assert(v(0)._1 == "a")
-        assert(v(0)._2 == "b")
-
-        assert(v(1)._1 == null)
-        assert(v(1)._2 == "c")
-
-        assert(v(2)._1 == null)
-        assert(v(2)._2 == "d")
-
-        assert(v(3)._1 == "minus")
-        assert(v(3)._2 == null)
-
-        assert(v(4)._1 == "d")
-        assert(v(4)._2 == "")
-    }
-
-    it should "properly parse quoted arguments" in {
-        val v = parseArgs("-a='b 'c' d' -minus -d=")
-
-        assert(v.size == 3)
-
-        assert(v(0)._1 == "a")
-        assert(v(0)._2 == "b 'c' d")
-
-        assert(v(1)._1 == "minus")
-        assert(v(1)._2 == null)
-
-        assert(v(2)._1 == "d")
-        assert(v(2)._2 == "")
-    }
-}

Reply via email to