AsyncAPI 3.x: the action and individual a search holds - #1711
AsyncAPI 3.x: the action and individual a search holds#1711LautaroPetaccio wants to merge 10 commits into
Conversation
f5a5dd5 to
fee5769
Compare
fee5769 to
cef304b
Compare
cef304b to
bc8930e
Compare
bc8930e to
7f14a88
Compare
7f14a88 to
2fe6c8d
Compare
2fe6c8d to
17bd03e
Compare
17bd03e to
d712fe2
Compare
d712fe2 to
0b02805
Compare
0b02805 to
25df3bf
Compare
25df3bf to
d9376a5
Compare
| } | ||
|
|
||
| //a field that is no longer there cannot be required either | ||
| (copy.get("required") as? ArrayNode)?.let { required -> |
There was a problem hiding this comment.
replace strings with constants
There was a problem hiding this comment.
Done everywhere in this PR.
| * There is one individual for every transport rather than one per transport: Kafka versus AMQP | ||
| * versus a socket appears nowhere in here. What is being searched over is the operation and the | ||
| * payload, which are the same whatever moves the bytes; which wire is used is decided below the | ||
| * driver interface. Were the transport to leak in here there would have to be a |
| mainSize = groupsView()!!.sizeOfGroup(GroupsOfChildren.MAIN), | ||
| sqlSize = groupsView()!!.sizeOfGroup(GroupsOfChildren.INITIALIZATION_SQL), | ||
| mongoSize = groupsView()!!.sizeOfGroup(GroupsOfChildren.INITIALIZATION_MONGO), | ||
| redisSize = groupsView()!!.sizeOfGroup(GroupsOfChildren.INITIALIZATION_REDIS), |
There was a problem hiding this comment.
I think that we should keep redis outside ASYNC API until it is fully supported in REST
There was a problem hiding this comment.
Dropped the redisSize parameter, the group is fixed at zero, and copyContent no longer measures it.
d9376a5 to
ee8e1bf
Compare
| * a keyword either. | ||
| */ | ||
| private val DATA_KEYWORDS = setOf("const", "default", "enum", "example", "examples") | ||
| private val DATA_KEYWORDS = setOf(CONST, DEFAULT, ENUM, EXAMPLE, EXAMPLES) |
There was a problem hiding this comment.
recall what stated in for_developers.md. do not declare variables in the middle of the file, but at the top of the class
| * document, so a field a service happens to call "const" or "default" must still be walked. | ||
| */ | ||
| private val SCHEMA_MAPS = setOf("properties", "patternProperties", "definitions", "\$defs") | ||
| private val SCHEMA_MAPS = setOf(PROPERTIES, PATTERN_PROPERTIES, DEFINITIONS, DEFS) |
There was a problem hiding this comment.
do not declare variables in the middle/end of the file
| mainSize: Int = allActions.size, | ||
| sqlSize: Int = 0, | ||
| mongoSize: Int = 0, | ||
| dnsSize: Int = 0, |
There was a problem hiding this comment.
we are adding several more DB to EvoMaster these days. no need to handle them here, for the moment. but can leave a TODO comment about it
60d5918 to
3e3dd4e
Compare
3e3dd4e to
9709fab
Compare
9709fab to
621abde
Compare
621abde to
07e585e
Compare
07e585e to
8fc83db
Compare
5e4064a to
eec4004
Compare
Turns the parsed document into something the search can sample and mutate. AsyncApiAction is one message published on one channel, following the shape of RPCCallAction -- the closest analogue in EvoMaster, being a call with no URL, made through a driver, whose mutable state is the input and whose response is read afterwards rather than searched over. What is deliberately not a gene is the point of the design: - the address, which the contract fixes. Sending to a channel the service does not read would only waste executions. - the correlation id, stamped fresh at each execution. Searching over it could achieve nothing, since the service only echoes it, and pairing a reply with its request needs a value unique per execution rather than one carried in the genome. The header it is stamped into is therefore left out of the header genes, and when it is the only header there are no header genes at all -- an empty schema would otherwise build a free-form map and invite the search to invent headers the contract never declared. - the reply, which is an observation, read at fitness time. AsyncApiIndividual is one individual for every transport rather than one per transport: Kafka versus AMQP versus a socket appears nowhere in it. What is searched over is the operation and the payload, which are the same whatever moves the bytes. AsyncApiActionBuilder fills an action cluster, keeping the contract the REST and GraphQL builders use: one entry per action name, and a list of what had to be skipped rather than an exception. Only operations the service consumes become actions, since a 'send' is something to subscribe to rather than to drive. An operation carrying several messages becomes several actions -- which message to send is a choice made by picking an action, not by mutating a gene -- and the message is named in the action only when there is more than one, so a generated test reads as the operation where it can. That multi-message case is not hypothetical, but it does not arise the way one would expect. No document in the corpus narrows to more than one message with a `messages:` array; what happens is the opposite -- an operation declares no array at all, and so inherits everything its channel carries. scalar.yaml is the real case, vendored unmodified under MIT with its source noted: its userEvents channel carries five genuinely different payloads, and subscribeToUserEvents does not say which of them it means. Note RPCIndividual.seeIndexedRPCCalls is not copied over. It looks up children by action type, but the children are enterprise action groups, so it returns nothing; it has no callers. seeMainExecutableActions does the job.
It is vendored unmodified from github.com/scalar/scalar under MIT and names its source at the top of the file, but docs/for_developers.md also asks for third-party material to be listed in docs/reused_code.md.
Review feedback: the keywords read and written while turning a payload into genes -- properties, required, const, enum, type, minimum, maximum and the type names -- were literals at fifteen sites, two of them also inside the DATA_KEYWORDS and SCHEMA_MAPS sets. They are object-level constants now, beside INLINE_PREFIX, and the two sets are built from them. These are JSON Schema's vocabulary rather than AsyncAPI's, so they belong here and not with the parser's keywords.
Review feedback: keep Redis out of AsyncAPI until it is fully supported for REST. Every Redis option in EMConfig is still @experimental, so a new problem type should not inherit that seam on day one. The redisSize parameter goes, the group size is fixed at zero, and copyContent no longer measures it. Mongo and DNS stay: neither is experimental. RPCIndividual and RestIndividual both still carry a Redis group; this is deliberately stricter than the classes it is modelled on.
Review feedback asked where the transport is. The KDoc said "below the driver interface" without naming it; it now says SutController.executeAsyncApiAction, the one driver method that publishes and awaits, so the reference can be found by search. The core hands it an address, a payload and a correlation id, and never learns what broker is behind them.
Review feedback: DATA_KEYWORDS and SCHEMA_MAPS were declared after every function, and AsyncApiAction.singleMessage after its first override. docs/for_developers.md puts fields first. The two sets now follow the keyword constants they are built from, and singleMessage opens the class body.
Review feedback: EvoMaster is adding several more databases; they need no handling here yet, but a TODO beside the three that are handled says where they will go.
Review against docs/for_developers.md: a suite is named after the class it exercises, and the four tests of AsyncApiIndividual were sitting in AsyncApiActionBuilderTest. Moved, unchanged, to AsyncApiIndividualTest.
addAction and removeAction took any position and left the group bookkeeping to object, which it does only when the index falls off the children altogether. With a setup action in front of the messages, removing "message -1" removed the setup action instead. Both now check the position against the main group, as RestIndividual does, and say so.
…ses microcks.yaml too addActionsFromSchema clears the cluster it is given before filling it, as the REST builder does; its KDoc now says so. reused_code.md said microcks.yaml was a test resource of the parser module only, but a copy sits in core as well since the action builder tests.
eec4004 to
07e181b
Compare
Eighth in the AsyncAPI stack, on top of #6. Turns the parsed document into something a search can sample and mutate.
The action
AsyncApiActionis one message published on one channel, following the shape ofRPCCallAction— the closest analogue in EvoMaster, being a call with no URL, made through a driver, whose mutable state is the input and whose response is read afterwards rather than searched over.What is deliberately not a gene is the design.
The individual
AsyncApiIndividualis one individual for every transport rather than one per transport. Kafka versus AMQP versus a socket appears nowhere in it: what is searched over is the operation and the payload, which are the same whatever moves the bytes, and which wire is used is decided below the driver interface. Were the transport to leak in here there would have to be aKafkaIndividualand anAmqpIndividualwith nothing shared between them.The builder
AsyncApiActionBuilderfills an action cluster, keeping the contractaddActionsFromSwaggerandaddActionsFromSchemaalready use: one entry per action name, and a list of what had to be skipped rather than an exception.Two decisions worth review:
sendoperation is what the service emits — something to subscribe to, not to drive. They are counted as skipped rather than built.recv_list_legsrather thanrecv_list_legs:listLegs), so a generated test reads as the operation wherever it can.One thing not copied across
RPCIndividual.seeIndexedRPCCallslooks up children by action type, but the children areEnterpriseActionGroups, so it returns nothing. It has no callers, so it appears to be dead. I wrote the same method here, watched a test fail on it, and removed it rather than carrying the bug over —seeMainExecutableActionsdoes the job. Worth a look on the RPC side.Testing
15 new tests in
AsyncApiActionBuilderTest, covering the action cluster built from NCS, microcks and a WebSocket document, what an action does and does not expose as genes, adding and removing messages from an individual, and copying one. 108 across the AsyncAPI package.