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

Add transaction list CLI command. #532

Merged
merged 9 commits into from Jul 24, 2019

Conversation

jonathanknowles
Copy link
Member

@jonathanknowles jonathanknowles commented Jul 12, 2019

Issue Number

#467

Overview

I have:

  • added a transaction list command to the CLI, which takes optional --start TIME and --end TIME parameters.
  • added a CLI unit test to demonstrate that transaction list --help displays the expected help text.
  • added a CLI integration test to confirm that transaction list returns [] for a brand new wallet, regardless of what values are provided for --start or -end (as expected).

Outstanding work for future PRs

The listTransactions endpoint is not yet implemented, currently returning [].

Therefore, the tests introduced in this PR are limited in their scope.

Once the listTransactions endpoint is implemented, we can add the following tests in future PRs:

  • CLI integration tests to confirm that the full set of transactions is returned when neither --start nor --end are specified.
  • CLI integration tests to confirm that appropriate subsets of transactions are returned, in the correct order, when either --start or --end are specified (or both).

@jonathanknowles jonathanknowles self-assigned this Jul 12, 2019
@jonathanknowles jonathanknowles force-pushed the jonathanknowles/cli-iso-8601-time branch 2 times, most recently from 0e1e728 to 49341e7 Compare July 15, 2019 08:31
@jonathanknowles jonathanknowles force-pushed the jonathanknowles/cli-list-transactions branch from 6f7b68a to 11e0c1b Compare July 15, 2019 08:31
@jonathanknowles jonathanknowles changed the base branch from jonathanknowles/cli-iso-8601-time to master July 16, 2019 01:28
@jonathanknowles jonathanknowles force-pushed the jonathanknowles/cli-list-transactions branch 2 times, most recently from 19d982b to 98e06cc Compare July 16, 2019 08:02
@jonathanknowles jonathanknowles force-pushed the jonathanknowles/cli-list-transactions branch 7 times, most recently from 5bfc600 to 4e9a90c Compare July 22, 2019 03:30
@jonathanknowles jonathanknowles changed the title WIP: Add transaction list CLI command. Add transaction list CLI command. Jul 22, 2019
@jonathanknowles jonathanknowles force-pushed the jonathanknowles/cli-list-transactions branch from 4e9a90c to 74884f2 Compare July 22, 2019 03:35
@jonathanknowles jonathanknowles marked this pull request as ready for review July 22, 2019 03:35
@@ -644,6 +651,17 @@ spec = do
out `shouldBe` ""
c `shouldBe` ExitFailure 1

it "TRANS_LIST_01 - Listing transactions for an empty wallet" $ \ctx ->
withMaxSuccess 10 $ property $ \mAfter mBefore -> do
Copy link
Member Author

Choose a reason for hiding this comment

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

This property is rather slow, so we only check it a few times.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe integration tests layer is therefore not the best place for properties? I think that more value we can gain from adding some negative cases here (see my previous comment) and have properties like this on unit level...

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe integration tests layer is therefore not the best place for properties? I think that more value we can gain from adding some negative cases here (see my previous comment) and have properties like this on unit level...

Hmm, I wonder if there's a good reason to avoid using properties here?

My intent here was to cover all the cases for --after and --before. (Both of these parameters can be either present or absent.) The point is that the values can be anything, and the result should still be [].

It seemed sensible to generate these cases rather than write them manually. But perhaps there is a better way?

Copy link
Contributor

Choose a reason for hiding this comment

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

It seemed sensible to generate these cases rather than write them manually. But perhaps there is a better way?

I agree ^.

By saying:

Maybe integration tests layer is therefore not the best place for properties?

I was reffering to your comment:

This property is rather slow, so we only check it a few times.

I was thinking that maybe it just takes a lot of time on this level and that's why I though that bringing it to unit level would make it faster...

Copy link
Member Author

Choose a reason for hiding this comment

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

This property is rather slow, so we only check it a few times.

I was thinking that maybe it just takes a lot of time on this level and that's why I though that bringing it to unit level would make it faster...

Good point. I guess it depends on what we deem acceptable. On my system, with 10 cases, it takes around 1-2 seconds to run. Is this fast enough?

Copy link
Contributor

Choose a reason for hiding this comment

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

On my system, with 10 cases, it takes around 1-2 seconds to run. Is this fast enough?

Yeah, I think that's OK in general. (on the other hand that may be the time of 1000 tests on unit level ;) )

There's also this concept of testing pyramid (https://medium.com/@timothy.cochran/test-pyramid-the-key-to-good-automated-test-strategy-9f3d7e3c02d5), which I'm fond of, which basically says to have the most tests on the lowest level of the system and the least on the highest - end-to-end level. Following this concept we could have say, property doing 1000 examples on unit test level testing a lot of different values and verify that proper error is thrown and have just one integration test with single value (or just a few values) testing if everything works fine end-to-end (e.g. check the error message is presented correctly to the user etc.)

Copy link
Member Author

Choose a reason for hiding this comment

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

There's also this concept of testing pyramid (https://medium.com/@timothy.cochran/test-pyramid-the-key-to-good-automated-test-strategy-9f3d7e3c02d5), which I'm fond of, which basically says to have the most tests on the lowest level of the system and the least on the highest - end-to-end level.

Thanks for sharing this, the content makes a lot of sense.

For this case though, I'm guessing we really would like to test all the following cases:

  1. Both --after and --before parameters present.
  2. Only --after present.
  3. Only --before present.
  4. Neither --after nor --before present.

In addition, to be able to test these parameters with random rather than fixed values, is probably useful.

We could make an argument for writing the above four cases as separate unit tests, but since all cases should produce the same output (the empty list), wouldn't that mean an unnecessary duplication of code? (Also, given that we only generate 10 cases, I'm guessing it wouldn't save us much time on each test run.)

Though having said that, I don't have a particularly strong preference in this case! If you have a strong preference, I would be happy to rewrite this without properties.

Copy link
Member

Choose a reason for hiding this comment

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

We avoid property-based tests in integration tests because:

Copy link
Member Author

Choose a reason for hiding this comment

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

@KtorZ @piotr-iohk

Okay. I've:

  • changed the integration test to use a matrix of hand-picked time values (rather than using a property-based test).
  • changed the listTransactionsViaCLI function to take Maybe String for each time value.

Hopefully this should address the concerns raised above, but let me know if you'd like me to change anything about this.

Thanks again for looking at this PR. :)

, " --port INT port used for serving the wallet"
, " API. (default: 8090)"
, " --after TIME specifies an earliest time"
, " --before TIME specifies a latest time"
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice to add info about the time format (ISO-8601 UTC) and maybe exemplary value.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a good idea. I'll add it.

Copy link
Member Author

Choose a reason for hiding this comment

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

@piotr-iohk Added:

transaction list --help
Available options:
  -h,--help                Show this help text
  --port INT               port used for serving the wallet API. (default: 8090)
  --after TIME             specifies an earliest time (ISO 8601 format: basic or extended)
  --before TIME            specifies a latest time (ISO 8601 format: basic or extended)

=> s
-> ApiWallet
-> Maybe Iso8601Time
-> Maybe Iso8601Time
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 it would be better to have just a [String] as an argument of this method. This would allow for more flexibility when constructing tests, in particular we can add a lot of different negative tests (e.g. faulty wallet ID, typos in the parameter names, bad-formed parameter values etc.) which is not possible currently.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it would be better to have just a [String] as an argument of this method. This would allow for more flexibility when constructing tests, in particular we can add a lot of different negative tests (e.g. faulty wallet ID, typos in the parameter names, bad-formed parameter values etc.) which is not possible currently.

@piotr-iohk thanks again for looking at this.

I can sympathize with this argument. Though for this PR, I consciously avoided doing that due to feedback during previous reviews: for example: #519 (comment)

@KtorZ, would you be able to share your opinion on this?

Regarding the use of negative tests, I had some thoughts which I wanted to share here:

  1. Regarding simple typos in parameter names: rather than writing lots of manual tests (which are likely to be rather repetitive), perhaps there is a better, automated way to generate CLI calls with mis-spelt parameter names? We could potentially generate these from the CLI definition.

  2. Regarding badly-formed parameters that the CLI can detect due to parsing errors (i.e., fromText returning Left). Again, perhaps there is a way to generate these automatically? (Using QuickCheck, we can generate arbitrary values that we know will not parse with fromText, and pass these to the CLI, expecting failure.)

  3. Regarding invalid parameters that parse correctly, whose invalidity can only be detected by the back-end. Because the CLI must first parse data from Text to well-typed values before sending it to the back end, I suspect this case also doesn't require the use of String types.

@piotr-iohk Would be interested to hear your opinion!

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks @jonathanknowles!

I think the way I'm coming from is just the past experience: In https://github.com/input-output-hk/cardano-wallet-legacy we actually had a strongly typed API client and it used to be quite limiting for me in terms of flexibility to create test cases (in particularly negative) (see examplary request -> https://github.com/input-output-hk/cardano-wallet-legacy/blob/develop/test/integration/Test/Integration/Scenario/Transactions.hs#L255-L262). As an aid there was this unsafeRequest added later which was less typed but it was giving more flexibility (e.g. https://github.com/input-output-hk/cardano-wallet-legacy/blob/develop/test/integration/Test/Integration/Scenario/EosWallets.hs#L59-L69). So in this iteration of wallet we kind of went for the second approach from the beggining.

In my mind the idea of automated integration test is just to have a tool to be able to make the same calls and get the same responses (and test them) as the end user would (and user can basically type anything ;))
Off course if there is a room for improving this, I'm all for it (in particular for generating all sort of negative test cases). The only thing that I would not want to achieve is that any additional layers of abstraction become something that limit us in testing.

Copy link
Member

Choose a reason for hiding this comment

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

Having a stringly-typed API makes for a quite poor documentation when reading function signatures. Yet, having said that, there's not much we do with the underlying data-type apart from "showing it". Plus, we do want to submit values that are not valid and therefore, that couldn't be represented as an Iso8601Range. Most of the integration tests work this way for this very reason as @piotr-iohk highlighted already.

Regarding the automated generation of false cases at the integration level: sounds like overkill and probably too complicated at this stage. We can already test all sort of things at the unit level with extensive properties and all sort of negative tests. Plus, integration tests are already quite complicated on their own, so we have to strive to avoid this complexity from exploding. Mixing property tests at this stage would require some careful thoughts and design for something we can already do very well at the unit level.

Copy link
Member Author

Choose a reason for hiding this comment

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

@KtorZ @piotr-iohk

Okay. I've:

  • changed the integration test to use a matrix of hand-picked time values (rather than using a property-based test).
  • changed the listTransactionsViaCLI function to take Maybe String for each time value.

Hopefully this should address the concerns raised above, but let me know if you'd like me to change anything about this.

Copy link
Member Author

Choose a reason for hiding this comment

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

@KtorZ wrote:

Regarding the automated generation of false cases at the integration level: sounds like overkill and probably too complicated at this stage.

My point is that "typos in the parameter names" was used as a justification for allowing parameters to be supplied as [String] in the listTransactionsViaCLI command:

Assuming we decide that it's valuable to test that parameter name misspellings are rejected, wouldn't it be better to generate such tests automatically from the CLI definition? (as part of a unit test suite.)

It seems like there would be countless permutations, especially when we take all commands and argument combinations into account.

Copy link
Contributor

Choose a reason for hiding this comment

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

Btw. another advantage of [String] is also that we can test different order of parameters (--start ... --end ... or --end ... --start ...)

@@ -644,6 +651,17 @@ spec = do
out `shouldBe` ""
c `shouldBe` ExitFailure 1

it "TRANS_LIST_01 - Listing transactions for an empty wallet" $ \ctx ->
withMaxSuccess 10 $ property $ \mAfter mBefore -> do
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe integration tests layer is therefore not the best place for properties? I think that more value we can gain from adding some negative cases here (see my previous comment) and have properties like this on unit level...

Copy link
Contributor

@rvl rvl 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

@jonathanknowles jonathanknowles force-pushed the jonathanknowles/cli-list-transactions branch from 15e014c to 38c0bf7 Compare July 22, 2019 07:46
@jonathanknowles
Copy link
Member Author

I've changed the CLI time range arguments to --start and --end in line with the discussion here: #467 (comment)

, maybe [] (\t -> ["--start", showT t]) mTimeRangeStart
, maybe [] (\t -> ["--end", showT t]) mTimeRangeEnd
, maybe [] (\t -> ["--start", t]) mTimeRangeStart
, maybe [] (\t -> ["--end", t]) mTimeRangeEnd
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd still be after using just [String] rather than ApiWallet -> Maybe String -> Maybe String 😅 because:

  • we cannot provide faulty walletId.
  • also we're not able to provide invalid argument like --star...

(I know, I know... if you're developer, your eyes must hurt when you see this ;) )

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd still be after using just [String] rather than ApiWallet -> Maybe String -> Maybe String sweat_smile because:
(I know, I know... if you're developer, your eyes must hurt when you see this ;) )

It's okay, I have a pair of special developer goggles. 😅

No problem, I've updated the listTransactionsViaCLI function as requested.

However, I do still have some reservations.

Given that this function is intended to be part of a DSL, it seems we've drawn the line rather arbitrarily on which parts of the command should be freeform, and which parts should be hard-coded. If we allow the arguments to be [String] (thus allowing invalid variations), then why hard-code the transaction list command prefix (thus disallowing invalid variations like transaction lost and so on)?

also we're not able to provide invalid argument like --star...

I would question whether we really want to be building integration tests that check misspelled CLI arguments are rejected. It seems like there would be countless permutations, especially when we take all commands and argument combinations into account.

Surely, if we decide that it's valuable to test for misspellings, wouldn't it be better to generate such tests automatically from the CLI definition? (as part of a unit test suite.)

Copy link
Contributor

Choose a reason for hiding this comment

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

Given that this function is intended to be part of a DSL, it seems we've drawn the line rather arbitrarily on which parts of the command should be freeform, and which parts should be hard-coded. If we allow the >arguments to be [String] (thus allowing invalid variations), then why hard-code the transaction list command prefix (thus disallowing invalid variations like transaction lost and so on)?

Indeed, it is like just a shortcut to test different cases of transaction list. Also there is actually a special test case that roughly covers cases like transaction lost -> https://github.com/input-output-hk/cardano-wallet/blob/master/lib/core/test/integration/Test/Integration/Scenario/CLI/Miscellaneous.hs#L38-L102, so it will surely land there.

I would question whether we really want to be building integration tests that check misspelled CLI arguments are rejected. It seems like there would be countless permutations, especially when we take all commands and argument combinations into account.

My opinion is that in integration test it is not necessary about providing all possible permutations but rather examples focusing on bonduary values and corner cases and having in mind equivalence partitioning. So --star and --startt would be probably enough to test misspelled --start,

  • they are sort of boundary values and kind of corner(ish) (very similar to --start yet different in length),
  • Also I might assume that if they give expected result than pretty much other misspells will, so I don't need to test all possible combinations (equivalence partitioning) [well, for sanity I would probably test also some weird strings ;)]

Btw. another advantage of [String] is also that we can test different order of parameters (--start ... --end ... or --end ... --start ...)

Surely, if we decide that it's valuable to test for misspellings, wouldn't it be better to generate such tests automatically from the CLI definition? (as part of a unit test suite.)

I think that testing misspellings on integration level is probably good enough, but perhaps that would be also a nice option.

jonathanknowles added a commit that referenced this pull request Jul 24, 2019
…re` arguments.

In the case of these arguments, we accept ISO 8601 format strings, either in
basic format or extended format.
Use `--start` and `--end` instead of `--after` and `--before`.

See: #467 (comment)
@jonathanknowles jonathanknowles force-pushed the jonathanknowles/cli-list-transactions branch from 2bcd588 to 52ad301 Compare July 24, 2019 02:44
Copy link
Contributor

@piotr-iohk piotr-iohk left a comment

Choose a reason for hiding this comment

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

Thanks! 👍

@jonathanknowles jonathanknowles merged commit a09e08a into master Jul 24, 2019
@jonathanknowles jonathanknowles deleted the jonathanknowles/cli-list-transactions branch July 24, 2019 06:57
@jonathanknowles
Copy link
Member Author

Thanks! +1

@piotr-iohk thanks again for your thorough review, I appreciate our discussion.

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

4 participants