diff --git a/vuu/src/main/scala/org/finos/vuu/api/TableDef.scala b/vuu/src/main/scala/org/finos/vuu/api/TableDef.scala index 0a11aaf2a..f0f7a864d 100644 --- a/vuu/src/main/scala/org/finos/vuu/api/TableDef.scala +++ b/vuu/src/main/scala/org/finos/vuu/api/TableDef.scala @@ -53,6 +53,10 @@ object TableDef { def apply(name: String, keyField: String, columns: Array[Column], joinFields: String*): TableDef = { new TableDef(name, keyField, columns, joinFields, indices = Indices()) } + + def apply(name: String, keyField: String, columns: Array[Column], invisible: Boolean, joinFields: String*): TableDef = { + new TableDef(name, keyField, columns, joinFields, indices = Indices(), invisible = invisible) + } } object AutoSubscribeTableDef { @@ -122,7 +126,8 @@ class TableDef(val name: String, val joinFields: Seq[String], val autosubscribe: Boolean = false, val links: VisualLinks = VisualLinks(), - val indices: Indices) extends VuuInMemPluginLocator { + val indices: Indices, + val invisible: Boolean = false) extends VuuInMemPluginLocator { private val createdTimeColumn: SimpleColumn = SimpleColumn(CreatedTimeColumnName, customColumns.length, DataType.fromString("long")) private val updatedTimeColumn: SimpleColumn = SimpleColumn(LastUpdatedTimeColumnName, customColumns.length + 1, DataType.fromString("long")) diff --git a/vuu/src/main/scala/org/finos/vuu/core/CoreServerApiHandler.scala b/vuu/src/main/scala/org/finos/vuu/core/CoreServerApiHandler.scala index 7abf0e20b..194854989 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/CoreServerApiHandler.scala +++ b/vuu/src/main/scala/org/finos/vuu/core/CoreServerApiHandler.scala @@ -315,9 +315,9 @@ class CoreServerApiHandler(val viewPortContainer: ViewPortContainer, val table = tableContainer.getTable(msg.table.table) - if (table == null) - errorMsg(s"no table found for ${msg.table}")(ctx) - else { + if (table == null || table.getTableDef.invisible) { + vsMsg(CreateViewPortReject(msg.table, s"no table found for ${msg.table}"))(ctx) + } else { val columns = if (msg.columns.length == 1 && msg.columns(0) == "*") { logger.trace("[CreateViewPortRequest] Wildcard specified for columns, going to return all") diff --git a/vuu/src/test/scala/org/finos/vuu/viewport/AbstractViewPortTestCase.scala b/vuu/src/test/scala/org/finos/vuu/viewport/AbstractViewPortTestCase.scala index 0c14ad6a3..fcf62ed46 100644 --- a/vuu/src/test/scala/org/finos/vuu/viewport/AbstractViewPortTestCase.scala +++ b/vuu/src/test/scala/org/finos/vuu/viewport/AbstractViewPortTestCase.scala @@ -36,8 +36,6 @@ class AbstractViewPortTestCase extends AnyFeatureSpec { def createDefaultViewPortInfra()(implicit clock: Clock, metrics: MetricsProvider): (ViewPortContainer, DataTable, MockProvider, ClientSessionId, OutboundRowPublishQueue) = { implicit val lifecycle: LifecycleContainer = new LifecycleContainer - val dateTime = 1437728400000L //new LocalDateTime(2015, 7, 24, 11, 0).toDateTime.toInstant.getMillis - val ordersDef = TableDef( name = "orders", keyField = "orderId", @@ -85,11 +83,65 @@ class AbstractViewPortTestCase extends AnyFeatureSpec { (viewPortContainer, orders, ordersProvider, session, outQueue) } + def createDefaultViewPortInfraWithInvisibleTable()(implicit clock: Clock, metrics: MetricsProvider): (ViewPortContainer, DataTable, MockProvider, ClientSessionId, OutboundRowPublishQueue) = { + implicit val lifecycle: LifecycleContainer = new LifecycleContainer - def createDefaultOrderPricesViewPortInfra()(implicit clock: Clock, metrics: MetricsProvider): (ViewPortContainer, DataTable, MockProvider, DataTable, MockProvider, ClientSessionId, OutboundRowPublishQueue) = { - implicit val lifecycle = new LifecycleContainer + val ordersDef = TableDef( + name = "orders", + keyField = "orderId", + columns = Columns.fromNames("orderId:String", "trader:String", "ric:String", "tradeTime:Long", "quantity:Int"), + invisible = true, + joinFields = "ric", "orderId" + ) + + val pricesDef = TableDef( + "prices", + "ric", + Columns.fromNames("ric:String", "bid:Double", "ask:Double", "last:Double", "open:Double", "close:Double"), + invisible = true, + "ric") + + val joinDef = JoinTableDef( + name = "orderPrices", + baseTable = ordersDef, + joinColumns = Columns.allFrom(ordersDef) ++ Columns.allFromExcept(pricesDef, "ric"), + joins = + JoinTo( + table = pricesDef, + joinSpec = JoinSpec(left = "ric", right = "ric", LeftOuterJoin) + ), + links = VisualLinks(), + joinFields = Seq() + ) - val dateTime = 1437728400000L //new LocalDateTime(2015, 7, 24, 11, 0).toDateTime.toInstant.getMillis + val joinProvider = JoinTableProviderImpl() + + val tableContainer = new TableContainer(joinProvider) + + val orders = tableContainer.createTable(ordersDef) + val prices = tableContainer.createTable(pricesDef) + val orderPrices = tableContainer.createJoinTable(joinDef) + + val ordersProvider = new MockProvider(orders) + val pricesProvider = new MockProvider(prices) + + val providerContainer = new ProviderContainer(joinProvider) + + val viewPortContainer = setupViewPort(tableContainer, providerContainer) + + joinProvider.start() + + joinProvider.runOnce() + + val session = ClientSessionId("sess-01", "chris") + + val outQueue = new OutboundRowPublishQueue() + + (viewPortContainer, orders, ordersProvider, session, outQueue) + } + + def createDefaultOrderPricesViewPortInfra()(implicit clock: Clock, metrics: MetricsProvider): (ViewPortContainer, DataTable, MockProvider, DataTable, MockProvider, ClientSessionId, OutboundRowPublishQueue) = { + implicit val lifecycle: LifecycleContainer = new LifecycleContainer val ordersDef = TableDef( name = "orders", diff --git a/vuu/src/test/scala/org/finos/vuu/viewport/validation/CreateValidViewportTest.scala b/vuu/src/test/scala/org/finos/vuu/viewport/validation/CreateValidViewportTest.scala index be0d6ac6f..90f1a694b 100644 --- a/vuu/src/test/scala/org/finos/vuu/viewport/validation/CreateValidViewportTest.scala +++ b/vuu/src/test/scala/org/finos/vuu/viewport/validation/CreateValidViewportTest.scala @@ -1,10 +1,9 @@ package org.finos.vuu.viewport.validation import org.finos.toolbox.jmx.{MetricsProvider, MetricsProviderImpl} -import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.time.{Clock, TestFriendlyClock} import org.finos.vuu.core.CoreServerApiHandler -import org.finos.vuu.net.{ClientSessionId, CreateViewPortRequest, RequestContext} +import org.finos.vuu.net.{ClientSessionId, CreateViewPortReject, CreateViewPortRequest, CreateViewPortSuccess, RequestContext, ViewServerMessage} import org.finos.vuu.viewport.{AbstractViewPortTestCase, ViewPortRange, ViewPortTable} import org.scalatest.GivenWhenThen import org.scalatest.matchers.should.Matchers @@ -17,10 +16,9 @@ class CreateValidViewportTest extends AbstractViewPortTestCase with Matchers wit implicit val clock: Clock = new TestFriendlyClock(1311544800) implicit val metrics: MetricsProvider = new MetricsProviderImpl - implicit val lifecycle: LifecycleContainer = new LifecycleContainer Given("we've created a viewport with orders in") - val (viewPortContainer, _, _, prices, _, _, outQueue) = createDefaultOrderPricesViewPortInfra() + val (viewPortContainer, _, _, _, _, _, outQueue) = createDefaultOrderPricesViewPortInfra() val api = new CoreServerApiHandler(viewPortContainer, tableContainer = viewPortContainer.tableContainer, providers = viewPortContainer.providerContainer) @@ -28,10 +26,58 @@ class CreateValidViewportTest extends AbstractViewPortTestCase with Matchers wit val ctx = RequestContext("req-101", ClientSessionId("A", "A"), outQueue, "token-0001") - val exception = intercept[Exception]{ + val exception = intercept[Exception] { api.process(CreateViewPortRequest(ViewPortTable("orders", "TEST"), ViewPortRange(0, 100), vpcolumnsOrders.toArray))(ctx) } exception.getMessage should startWith("Invalid columns specified in viewport request") } + + Scenario("create viewport for visible table, return success message") { + implicit val clock: Clock = new TestFriendlyClock(1311544800) + implicit val metrics: MetricsProvider = new MetricsProviderImpl + + Given("we've created a viewport with orders in") + val (viewPortContainer, _, _, _, outQueue) = createDefaultViewPortInfra() + + val api = new CoreServerApiHandler(viewPortContainer, tableContainer = viewPortContainer.tableContainer, providers = viewPortContainer.providerContainer) + val ctx = RequestContext("req-101", ClientSessionId("A", "A"), outQueue, "token-0001") + + val result: Option[ViewServerMessage] = api.process(CreateViewPortRequest(ViewPortTable("orders", "TEST"), ViewPortRange(0, 100), Array("orderId")))(ctx) + result.isDefined shouldBe true + result.get.body.isInstanceOf[CreateViewPortSuccess] shouldBe true + result.get.body.asInstanceOf[CreateViewPortSuccess].table shouldBe "orders" + } + + Scenario("create viewport for invisible table, return reject message") { + implicit val clock: Clock = new TestFriendlyClock(1311544800) + implicit val metrics: MetricsProvider = new MetricsProviderImpl + + Given("we've created a viewport with orders in") + val (viewPortContainer, _, _, _, outQueue) = createDefaultViewPortInfraWithInvisibleTable() + val api = new CoreServerApiHandler(viewPortContainer, tableContainer = viewPortContainer.tableContainer, providers = viewPortContainer.providerContainer) + + val ctx = RequestContext("req-101", ClientSessionId("A", "A"), outQueue, "token-0001") + + val result: Option[ViewServerMessage] = api.process(CreateViewPortRequest(ViewPortTable("orders", "TEST"), ViewPortRange(0, 100), Array("orderId")))(ctx) + result.isDefined shouldBe true + result.get.body.isInstanceOf[CreateViewPortReject] shouldBe true + result.get.body.asInstanceOf[CreateViewPortReject].msg shouldBe "no table found for TEST:orders" + } + + Scenario("create viewport for a table that doesn't exist, return reject message") { + implicit val clock: Clock = new TestFriendlyClock(1311544800) + implicit val metrics: MetricsProvider = new MetricsProviderImpl + + Given("we've created a viewport with orders in") + val (viewPortContainer, _, _, _, outQueue) = createDefaultViewPortInfraWithInvisibleTable() + + val api = new CoreServerApiHandler(viewPortContainer, tableContainer = viewPortContainer.tableContainer, providers = viewPortContainer.providerContainer) + val ctx = RequestContext("req-101", ClientSessionId("A", "A"), outQueue, "token-0001") + + val result: Option[ViewServerMessage] = api.process(CreateViewPortRequest(ViewPortTable("random_table", "TEST"), ViewPortRange(0, 100), Array("orderId")))(ctx) + result.isDefined shouldBe true + result.get.body.isInstanceOf[CreateViewPortReject] shouldBe true + result.get.body.asInstanceOf[CreateViewPortReject].msg shouldBe "no table found for TEST:random_table" + } } }