Skip to content

Commit

Permalink
Merge pull request #412 from modelix/fix/modelql-unresolved-concept
Browse files Browse the repository at this point in the history
MODELIX-714 ModelQl query on model-server fails with "issue getting concept"
  • Loading branch information
mhuster23 authored Jan 25, 2024
2 parents bbee487 + fd8e483 commit b1fb03f
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 104 deletions.
17 changes: 15 additions & 2 deletions model-api-gen-gradle-test/ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

set -e
(
cd "$(dirname "$0")"
./gradlew build
TEST_DIR="$(dirname "$(readlink -f "$0")")"
cd "$TEST_DIR/../"
if [ "${CI}" != "true" ]; then
trap cleanup INT TERM EXIT
cleanup () {
kill "${MODEL_SERVER_PID}"
exit
}
fi
./gradlew :model-server:run --console=plain --args="-inmemory -port 28102" &
MODEL_SERVER_PID=$!

curl -X GET --retry 30 --retry-connrefused --retry-delay 1 http://localhost:28102/health
cd "$TEST_DIR"
./gradlew build --console=plain --stacktrace
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
*/
package org.modelix.modelql.typed

import io.ktor.client.HttpClient
import io.ktor.server.testing.testApplication
import jetbrains.mps.baseLanguage.C_ClassConcept
import jetbrains.mps.baseLanguage.C_IntegerType
import jetbrains.mps.baseLanguage.C_MinusExpression
Expand All @@ -32,19 +30,12 @@ import jetbrains.mps.core.xml.C_XmlDocument
import jetbrains.mps.core.xml.C_XmlFile
import jetbrains.mps.lang.editor.imageGen.C_ImageGenerator
import jetbrains.mps.lang.editor.imageGen.ImageGenerator
import org.modelix.apigen.test.ApigenTestLanguages
import org.modelix.metamodel.instanceOf
import org.modelix.metamodel.typed
import org.modelix.metamodel.untyped
import org.modelix.model.api.IBranch
import org.modelix.model.api.PBranch
import org.modelix.model.api.getRootNode
import org.modelix.model.api.INode
import org.modelix.model.api.remove
import org.modelix.model.api.resolve
import org.modelix.model.client.IdGenerator
import org.modelix.model.lazy.CLTree
import org.modelix.model.lazy.ObjectStoreCache
import org.modelix.model.persistent.MapBasedStore
import org.modelix.model.server.light.LightModelServer
import org.modelix.modelql.client.ModelQLClient
import org.modelix.modelql.core.asMono
import org.modelix.modelql.core.count
Expand Down Expand Up @@ -75,78 +66,62 @@ import org.modelix.modelql.gen.jetbrains.mps.lang.editor.imageGen.setNode
import org.modelix.modelql.untyped.children
import org.modelix.modelql.untyped.conceptReference
import org.modelix.modelql.untyped.descendants
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue

class TypedModelQLTest {
private lateinit var branch: IBranch

private fun runTest(block: suspend (HttpClient) -> Unit) = testApplication {
application {
LightModelServer(80, branch.getRootNode()).apply { installHandlers() }
}
val httpClient = createClient {
}
block(httpClient)
}

@BeforeTest
fun setup() {
ApigenTestLanguages.registerAll()
val tree = CLTree(ObjectStoreCache(MapBasedStore()))
branch = PBranch(tree, IdGenerator.getInstance(1))
val rootNode = branch.getRootNode()
branch.runWrite {
val cls1 = rootNode.addNewChild("classes", -1, C_ClassConcept.untyped()).typed<ClassConcept>()
cls1.apply {
name = "Math"
member.addNew(C_StaticMethodDeclaration).apply {
name = "plus"
returnType.setNew(C_IntegerType)
visibility.setNew(C_PublicVisibility)
val a = parameter.addNew().apply {
name = "a"
type.setNew(C_IntegerType)
}
val b = parameter.addNew().apply {
name = "b"
type.setNew(C_IntegerType)
}
body.setNew().apply {
statement.addNew(C_ReturnStatement).apply {
expression.setNew(C_PlusExpression).apply {
leftExpression.setNew(C_VariableReference).apply {
variableDeclaration = a
}
rightExpression.setNew(C_VariableReference).apply {
variableDeclaration = b
}
abstract class TypedModelQLTest {

abstract fun runTest(block: suspend (ModelQLClient) -> Unit)

protected fun createTestData(rootNode: INode) {
rootNode.allChildren.forEach { it.remove() }
val cls1 = rootNode.addNewChild("classes", -1, C_ClassConcept.untyped()).typed<ClassConcept>()
cls1.apply {
name = "Math"
member.addNew(C_StaticMethodDeclaration).apply {
name = "plus"
returnType.setNew(C_IntegerType)
visibility.setNew(C_PublicVisibility)
val a = parameter.addNew().apply {
name = "a"
type.setNew(C_IntegerType)
}
val b = parameter.addNew().apply {
name = "b"
type.setNew(C_IntegerType)
}
body.setNew().apply {
statement.addNew(C_ReturnStatement).apply {
expression.setNew(C_PlusExpression).apply {
leftExpression.setNew(C_VariableReference).apply {
variableDeclaration = a
}
rightExpression.setNew(C_VariableReference).apply {
variableDeclaration = b
}
}
}
}
}
// Example for optional reference
rootNode.addNewChild("imageGen", -1, C_ImageGenerator.untyped())
.typed<ImageGenerator>()
.apply { node = cls1 }
}
// Example for optional reference
rootNode.addNewChild("imageGen", -1, C_ImageGenerator.untyped())
.typed<ImageGenerator>()
.apply { node = cls1 }

// Example for single non-abstract child
rootNode.addNewChild("xmlFile", -1, C_XmlFile.untyped())
// Example for single non-abstract child
rootNode.addNewChild("xmlFile", -1, C_XmlFile.untyped())

// Example for mulitple non-abstract child
rootNode.addNewChild("xmlComment", -1, C_XmlComment.untyped())
}
// Example for mulitple non-abstract child
rootNode.addNewChild("xmlComment", -1, C_XmlComment.untyped())
}

@Test
fun simpleTest() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()
fun `simple query`() = runTest { client ->
val result: Int = client.query { root ->
root.children("classes").ofConcept(C_ClassConcept)
.member
Expand All @@ -157,22 +132,22 @@ class TypedModelQLTest {
}

@Test
fun test() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()
fun `complex query`() = runTest { client ->
val result: List<Pair<String, String>> = client.query { root ->
root.children("classes").ofConcept(C_ClassConcept)
.member
.ofConcept(C_StaticMethodDeclaration)
.filter { it.visibility.instanceOf(C_PublicVisibility) }
.map { it.name.zip(it.parameter.name.toList(), it.untyped().conceptReference()) }
.toList()
}.map { it.first to it.first + "(" + it.second.joinToString(", ") + ") [" + it.third?.resolve()?.getLongName() + "]" }
}.map {
it.first to it.first + "(" + it.second.joinToString(", ") + ") [" + it.third?.resolve()?.getLongName() + "]"
}
assertEquals(listOf("plus" to "plus(a, b) [jetbrains.mps.baseLanguage.StaticMethodDeclaration]"), result)
}

@Test
fun `get references`() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()
fun `get references`() = runTest { client ->
val usedVariables: Set<String> = client.query { root ->
root.children("classes").ofConcept(C_ClassConcept)
.member
Expand All @@ -187,8 +162,7 @@ class TypedModelQLTest {
}

@Test
fun `get references - fqName`() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()
fun `get references - fqName`() = runTest { client ->
val usedVariables: Set<String> = client.query { root ->
root.children("classes").ofConcept(C_ClassConcept)
.member
Expand All @@ -210,8 +184,7 @@ class TypedModelQLTest {
}

@Test
fun `node serialization`() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()
fun `node serialization`() = runTest { client ->
val result: List<StaticMethodDeclaration> = client.query { root ->
root.children("classes").ofConcept(C_ClassConcept)
.member
Expand All @@ -220,25 +193,23 @@ class TypedModelQLTest {
.untyped()
.toList()
}.map { it.typed<StaticMethodDeclaration>() }
assertEquals("plus", branch.computeRead { result[0].name })
assertEquals("plus", result[0].name)
}

@Test
fun `return typed node`() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()
fun `return typed node`() = runTest { client ->
val result: List<StaticMethodDeclaration> = client.query { root ->
root.children("classes").ofConcept(C_ClassConcept)
.member
.ofConcept(C_StaticMethodDeclaration)
.filter { it.visibility.instanceOf(C_PublicVisibility) }
.toList()
}
assertEquals("plus", branch.computeRead { result[0].name })
assertEquals("plus", result[0].name)
}

@Test
fun `set property`() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()
fun `set property`() = runTest { client ->
val expected = "myRenamedMethod"
client.query { root ->
root.children("classes").ofConcept(C_ClassConcept)
Expand All @@ -257,9 +228,7 @@ class TypedModelQLTest {
}

@Test
fun `set reference`() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()

fun `set reference`() = runTest { client ->
val oldValue = client.query { root ->
root.children("classes").ofConcept(C_ClassConcept)
.member
Expand Down Expand Up @@ -298,8 +267,7 @@ class TypedModelQLTest {
}

@Test
fun `set reference - null`() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()
fun `set reference - null`() = runTest { client ->
val oldValue = client.query { root ->
root.children("imageGen").ofConcept(C_ImageGenerator).first().node
}
Expand All @@ -316,9 +284,7 @@ class TypedModelQLTest {
}

@Test
fun `add new child`() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()

fun `add new child`() = runTest { client ->
val oldNumChildren = client.query { root ->
root.children("classes").ofConcept(C_ClassConcept)
.first()
Expand Down Expand Up @@ -346,8 +312,7 @@ class TypedModelQLTest {
}

@Test
fun `add new child - default concept`() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()
fun `add new child - default concept`() = runTest { client ->
client.query { root ->
root.descendants().ofConcept(C_XmlComment)
.first()
Expand All @@ -365,9 +330,7 @@ class TypedModelQLTest {
}

@Test
fun `set child`() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()

fun `set child`() = runTest { client ->
client.query { root ->
root.descendants().ofConcept(C_ReturnStatement)
.first()
Expand All @@ -382,8 +345,7 @@ class TypedModelQLTest {
}

@Test
fun `set child - default concept`() = runTest { httpClient ->
val client = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()
fun `set child - default concept`() = runTest { client ->
client.query { root ->
root.descendants().ofConcept(C_XmlFile)
.first()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.modelix.modelql.typed

import io.ktor.server.testing.testApplication
import org.modelix.apigen.test.ApigenTestLanguages
import org.modelix.model.api.IBranch
import org.modelix.model.api.PBranch
import org.modelix.model.api.getRootNode
import org.modelix.model.client.IdGenerator
import org.modelix.model.lazy.CLTree
import org.modelix.model.lazy.ObjectStoreCache
import org.modelix.model.persistent.MapBasedStore
import org.modelix.model.server.light.LightModelServer
import org.modelix.modelql.client.ModelQLClient
import kotlin.test.BeforeTest

class TypedModelQLTestWithLightModelServer : TypedModelQLTest() {
private lateinit var branch: IBranch

override fun runTest(block: suspend (ModelQLClient) -> Unit) = testApplication {
application {
LightModelServer(80, branch.getRootNode()).apply { installHandlers() }
}
val httpClient = createClient {
}
val modelQlClient = ModelQLClient.builder().url("http://localhost/query").httpClient(httpClient).build()
block(modelQlClient)
}

@BeforeTest
fun setup() {
ApigenTestLanguages.registerAll()
val tree = CLTree(ObjectStoreCache(MapBasedStore()))
branch = PBranch(tree, IdGenerator.getInstance(1))
branch.runWrite {
createTestData(branch.getRootNode())
}
}
}
Loading

0 comments on commit b1fb03f

Please sign in to comment.