Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic parsing of the mappings into our model #5

Merged
merged 2 commits into from
Mar 22, 2018
Merged

Conversation

katebee
Copy link
Contributor

@katebee katebee commented Mar 21, 2018

This is the happy path of parsing the mappings.

When parsing Contacts and Targets there is no checking for weirdness - we are trusting that the config will be in an acceptable format for now.

We will probably want to fail immediately and send a notification to the owners or the lambda if the parser runs into issues at any point. Aspirational test cases added is that is the best option.

err => Failure(err),
json => Success(json)
suc => Success(suc)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor point, but I would rename 'suc' to 'mappings' (or something similar)

tryJson.map { json =>
val mappings = json.hcursor.downField("mappings").as[List[Json]]
val c: HCursor = jsonTargets.hcursor
// TODO: do we want to return an empty list, or throw a error here?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest throwing an error in the future - if we don't have a target, we can't notify - and that's the primary function of this service, so we might as well fail fast!

???
}
val c: HCursor = jsonContacts.hcursor
// TODO: do we want to return an empty list, or throw a error here?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above

Copy link
Contributor

@jacobwinch jacobwinch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me 👍


private[models] def parseTargets(jsonTargets: Json): List[Target] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this could fail and thus should return a Result as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I would like to change this so we fail fast... yet for now I will feel happier picking it up after we have something working end to end 🙈


private[models] def parseTargets(jsonTargets: Json): List[Target] = {
def parseTarget(key: String, value: String): Option[Target] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why this fn is inlined? It could be a separate function and then it would be independently testable.

private[models] def parseTargets(jsonTargets: Json): List[Target] = {
def parseTarget(key: String, value: String): Option[Target] = {
key.toLowerCase match {
case "stack" => Some(Stack(value))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might confuse people because these tags are all (strangely) fussy about their case elsewhere. By convention we use Stack, App and Stage.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry, I missed the toLowerCase. Do we need to lower case it here, or can we just assume people will use the correct case? If you give people the chance to misconfigure something they will do it!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toLowerCase felt like an easy win for catching a small frustration that could creep into the test data or prod data. Maybe we should error, yet I feel casing is an easy thing to recover from.

If the config.json is ultimately going to be machine generated, where should the responsibility of sanity checking it fall? I feel like the json generator should hold the majority of that responsibility... and maybe that allows anghammarad to mostly trust the input string?


def parseMapping(json: Json): Result[(List[Target], List[Contact])] = {
???
keys.flatMap { key =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would this be clearer as a for comp? (I'm not sure, just wondering :-) )

Serialization.parseTargets(testJson) shouldEqual List(Stack("stack-1"), App("app-1"))
}

"will return a failure if it cannot parse the keys" ignore {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:-(

"will correctly return the contacts" in {
val testJson = parse(
"""{"email":"stack.email","hangouts":"stack.room"}"""
).getOrElse(Json.Null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just a get here? If this fails we want to know about it straight away. At the moment it'll return empty JSON and then we'll get a test failure. At that point it won't be clear whether the problem is in our function or the test data.

"""{"target":{"AwsAccount":"123456789"},"contacts":{"email":"awsAccount.email"}}"""
).getOrElse(Json.Null)

Serialization.parseMapping(testJson).getOrElse(Json.Null) shouldEqual Mapping(List(AwsAccount("123456789")), List(EmailAddress("awsAccount.email")))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you mix in OptionValues into the test class you can do anOption.value. This will fail the test if it is a None.


"will return a failure if the string is not valid json" in {
val brokenJsonString =
"""{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very hard to read! Can it be indented nicely? Makes it hard to see in what sense this is "broken". If it's just invalid JSON then would a very short invalid string by a reduced test case?

@katebee katebee merged commit 9934be0 into master Mar 22, 2018
@katebee katebee deleted the kw-mappings branch March 22, 2018 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants