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

[code-health]: reduce duplication in brontide test. #8631

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

Chinwendu20
Copy link
Contributor

Change Description

This pull request is an off shoot of the peer backup PR (currently halted): #8490

It removes the duplicity in creating a peer instance and starting a peer in brontide tests.

It does not require a change log.

Copy link

coderabbitai bot commented Apr 8, 2024

Important

Auto Review Skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The recent changes focus on refining the testing framework for peer-related functionalities in the project, emphasizing readability, maintainability, and test environment structuring. These updates optimize test peer creation, channel management, and overall test organization for improved efficiency and clarity.

Changes

Files Summary
peer/brontide_test.go Significant test function refactoring for channel operations, fee negotiations, and updates.
peer/test_utils.go Split createTestPeer into two functions for enhanced test environment management.

Poem by CodeRabbit 🐇

Among the code we swiftly bound,
Refactoring echoes, a testing sound.
With each change, our tests align,
Bugs uncovered, in a clear design.
🌟 To stronger code, we leap and play,
Ensuring peer channels pave the way.
🥕 Cheers to developers, minds so keen,
Together we build a robust code scene.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Chinwendu20
Copy link
Contributor Author

@ProofOfKeags

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Review Status

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 6377f98 and 7930403.
Files selected for processing (2)
  • peer/brontide_test.go (14 hunks)
  • peer/test_utils.go (12 hunks)
Additional comments not posted (13)
peer/test_utils.go (4)

53-64: Introduce testPeerChanEnv for structured test environment setup.

This new structure organizes the environment setup for testing peer channels, enhancing readability and maintainability.


50-93: > 📝 NOTE

This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [66-333]

Refactor createTestPeer into createTestPeerWithChannel.

The refactoring significantly improves the test setup by separating concerns between peer creation and channel setup. However, consider further modularizing the function to reduce its length and complexity.

- func createTestPeerWithChannel(t *testing.T, updateChan func(a, b *channeldb.OpenChannel)) (*testPeerChanEnv, error) {
+ // Suggested refactor into smaller, more focused functions.

534-728: Introduce testPeerParams for managing test parameters.

The introduction of testPeerParams structure is a positive change, making the test setup more organized and easier to manage.


731-805: Introduce startPeer for starting a peer with optional checks.

The addition of startPeer function, which includes optional checks, is a good practice for ensuring the peer starts as expected in tests. This enhances the robustness of the test suite.

peer/brontide_test.go (9)

38-43: Consider using a helper function for common test setup steps.

To improve code maintainability and reduce duplication, consider extracting the common setup steps into a helper function. This can include creating the test harness, extracting peers, and channels from the harness.


78-86: Duplicate setup code detected.

The setup code in this test function is similar to the setup in previous test functions. Consider refactoring to use a shared setup function to reduce code duplication and improve maintainability.


178-186: Repeated test setup code.

The test setup code is repeated across multiple test functions. Refactoring this into a shared setup function could enhance code readability and maintainability.


297-305: Repeated setup code in test functions.

The setup code is repeated in several test functions. Creating a shared setup function could help in reducing duplication and improving the maintainability of the test code.


479-487: Consider refactoring repeated setup code.

The setup code is repeated across multiple test functions. Refactoring this into a shared setup function could improve code maintainability and readability.


802-812: Use of a specific update function in test setup.

The use of test.update in the test setup is a good practice for customizing the test environment. Ensure that this pattern is consistently applied across all tests for better flexibility and maintainability.


965-972: Setting feature bits for testing.

The approach of setting feature bits directly on the peer's configuration for testing is effective. Ensure that the test cases cover all relevant combinations of feature bits to thoroughly test the behavior under different configurations.


1279-1285: Marking channel as borked for testing.

Marking the channel as borked to simplify the test setup is a practical approach. However, ensure that this does not mask potential issues that could arise in scenarios where the channel is not marked as borked.


1325-1330: Testing removal of pending channels.

The test for removing pending channels is important for ensuring the correct management of channel states. Consider adding more edge cases, such as attempting to remove a channel that was never added, to ensure robustness.

peer/test_utils.go Outdated Show resolved Hide resolved
@ProofOfKeags ProofOfKeags self-requested a review April 8, 2024 18:19
Copy link
Collaborator

@ProofOfKeags ProofOfKeags left a comment

Choose a reason for hiding this comment

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

Good consolidation overall. A couple of changes I'd like to see.

@@ -726,3 +727,79 @@ func createTestPeer(t *testing.T) *testPeerParams {
chanStatusMgr: chanStatusMgr,
}
}

func startPeer(t *testing.T, mockConn *mockMessageConn,
peer *Brontide, extraChecks ...func() error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please don't do this extraChecks thing. It doesn't operate on any values that are only accessible from the inner scope and makes the API much worse.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What are your suggestions on extending this function. See how it is used here:

lnd/peer/brontide_test.go

Lines 1465 to 1495 in 15c3107

startPeer(t, mockConn, alicePeer, func() error {
select {
// We expect to be sent the backup data on peer start.
case rawMsg := <-mockConn.writtenMessages:
msgReader := bytes.NewReader(rawMsg)
nextMsg, err := lnwire.ReadMessage(msgReader, 0)
if err != nil {
return err
}
msg, ok := nextMsg.(*lnwire.YourPeerStorage)
if !ok {
return errors.New("expected lnwire. " +
"YourPeerStorage type, " +
"got something else")
}
if !bytes.Equal(msg.Blob, sampleData) {
return fmt.Errorf("backup data "+
"received: %v differs from data sent"+
": %v", rawMsg, sampleData)
}
// Fail test if we do not receive it.
case <-time.After(timeout):
return errors.New("did not receive peer backup " +
"as expected")
}
return nil
})

Copy link
Collaborator

Choose a reason for hiding this comment

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

just run that function after startPeer there's no reason for it to be inside of the startPeer scope.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That check has to happen while the peer is starting up, we are testing for sending peer their data on reconnection. It happens while starting up the peer.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The function takes no arguments so its entire closure environment is captured prior to the run. If you are depending on the right ordering of state mutations of values defined outside the environment then this design is bad as it is thoroughly unintuitive and offers no explanation to the caller what should or should not be supplied in this list. Find another way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I make the closure accept mockconn as an argument, would it make this okay? or maybe buffer the channel but I will see how that would go.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed it, I will just add a bool value to it and write the test in the goroutine itself, when I need to extend,

@@ -643,3 +529,200 @@ func (m *mockMessageConn) LocalAddr() net.Addr {
func (m *mockMessageConn) Close() error {
return nil
}

type testPeerParams struct {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a friendly reminder that "params" is not a good struct name. Ask yourself why you are grouping it into a struct. How does this grouping of values function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How about testPeerEnv?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you offer an explanation as to why this particular set of struct properties was selected? I suspect the answer to this naming question lies in that explanation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They are values used in the function that callers of the startPeer function would like to have access to for tests

Copy link
Collaborator

Choose a reason for hiding this comment

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

All tests? What kinds of tests? What are you testing? I encourage you to think a bit deeper than the obvious representational description.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If you want to suggest a more descriptive name, you can go ahead, if not testPeerEnv seems good to me.

Copy link
Collaborator

Choose a reason for hiding this comment

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

call it peerTestContext

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think testPeerEnv and peerTestContext are the same?

Copy link
Collaborator

Choose a reason for hiding this comment

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

We already have examples in other parts of the codebase like

https://github.com/lightningnetwork/lnd/blob/master/htlcswitch/link_isolated_test.go#L13-L20

so my suggestion is to keep things consistent.

@Chinwendu20 Chinwendu20 changed the title [code-health]: Fix duplicity in brontide test. [code-health]: reduce duplicity in brontide test. Apr 8, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review Status

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 6377f98 and eaba9c8.
Files selected for processing (2)
  • peer/brontide_test.go (14 hunks)
  • peer/test_utils.go (12 hunks)
Files skipped from review as they are similar to previous changes (1)
  • peer/test_utils.go
Additional comments not posted (11)
peer/brontide_test.go (11)

38-41: Consider consolidating the setup code for creating test peers with channels into a helper function to reduce duplication across tests.


78-81: Ensure that the test setup code is not unnecessarily duplicated across test functions. If similar setup is used in multiple tests, consider using a setup helper function.


178-181: Repeated test setup code detected. Creating a shared setup function could improve maintainability and readability.


297-300: To avoid code duplication in test setups, consider implementing a shared setup function that can be reused across tests.


479-482: The pattern of duplicating test setup code is observed again. Utilizing a shared setup function could enhance code reuse and test structure.


802-812: The test setup code for creating a test peer with a channel is repeated. Consider refactoring this into a shared setup function to improve code reuse and readability.


965-972: The setup code for creating a test peer and setting feature bits is repeated across tests. Refactoring this into a shared setup function could streamline the test code.


1007-1011: Repeated setup code for creating a test peer and setting up custom message handling is observed. Consider refactoring into a shared setup function to enhance code organization.


1052-1057: The setup code for creating a test peer with a channel is duplicated. Implementing a shared setup function could improve code maintainability.


1279-1285: The pattern of duplicating setup code for creating a test peer with a channel is noted again. A shared setup function could simplify the test code structure.


1325-1330: Repeated setup code for creating a test peer with a channel is observed. Refactoring this into a shared setup function could enhance code reuse and test clarity.

// createTestPeerWithChannel creates a channel between two nodes, and returns a
// peer for one of the nodes, together with the channel seen from both nodes.
// It takes an updateChan function which can be used to modify the default
// values on the channel states for each peer.
func createTestPeerWithChannel(t *testing.T, notifier chainntnfs.ChainNotifier,
publTx chan *wire.MsgTx, updateChan func(a, b *channeldb.OpenChannel),
mockSwitch *mockMessageSwitch) (
*Brontide, *lnwallet.LightningChannel, error) {
*testPeerChanEnv, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't need to return a pointer to the testPeerChanEnv

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So that one can easily return nil? I also read that working with pointers is more memory efficient instead of copying struct into different memory addresses. It is also in line with what I have seen in the codebase

Copy link
Collaborator

Choose a reason for hiding this comment

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

In this case you can leave it. Discussions of efficiency are highly nuanced, and what you read isn't wrong, but it isn't right either. Also we are moving away from excessive pointer usage throughout the codebase. The reason to move away from pointer usage has to do with making the codebase less fragile over its lifetime when many many people will touch it. Robustness > efficiency 99% of the time.

peer/test_utils.go Outdated Show resolved Hide resolved
@@ -643,3 +529,200 @@ func (m *mockMessageConn) LocalAddr() net.Addr {
func (m *mockMessageConn) Close() error {
return nil
}

type peerTestCtx struct {
Copy link
Collaborator

Choose a reason for hiding this comment

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

how does this differ from the earlier specified testPeerChanEnv?

I actually think this is a pretty instructive example 🙂.

In the past you may have heard me say that naming things properly is important. This is what I mean when I say that bad naming can get out of control. If you don't have concrete concepts that bind things together, then you can end up in situations like this where we have a whole bunch of things that are almost the same with names that are vague and this makes it hard to understand when reading the code and even harder to remember which of these structs you need when writing new code.

Here we have two structs that seem to share a similar role and they have different permutations of the same vague name. How do I know when to use one instead of the other. Or do I give up and create a third

Either we need to consolidate these two ideas into a single one, or we need to clearly specify their difference and denote that in the naming and godoc so that people who touch this code next know which type to use in which situation. Naming may feel trivial but it reveals an imprecision in the ideas themselves.

So answer me this: why can't we use this instead of testPeerChanEnv?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On a second look, I think maybe it can be one struct. I have consolidated them.

Copy link
Collaborator

Choose a reason for hiding this comment

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

It looks like there is a commit in the middle where you have two copies of the same struct defined. You'll need to consolidate them in that fourth commit, rather than the last one, if you want the CI to accept it.

peer/test_utils.go Show resolved Hide resolved
@Chinwendu20 Chinwendu20 force-pushed the brontidetest branch 2 times, most recently from e682b30 to 8705c38 Compare April 18, 2024 02:59
Copy link
Collaborator

@ProofOfKeags ProofOfKeags left a comment

Choose a reason for hiding this comment

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

Well done!

@ProofOfKeags ProofOfKeags changed the title [code-health]: reduce duplicity in brontide test. [code-health]: reduce duplication in brontide test. Apr 25, 2024
@Chinwendu20 Chinwendu20 mentioned this pull request Apr 29, 2024
8 tasks
Copy link
Collaborator

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

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

Nice work! A few comments from my side 🙏

peer/brontide_test.go Outdated Show resolved Hide resolved
peer/test_utils.go Outdated Show resolved Hide resolved
peer/test_utils.go Outdated Show resolved Hide resolved
peer/brontide_test.go Outdated Show resolved Hide resolved
peer/test_utils.go Show resolved Hide resolved
peer/test_utils.go Show resolved Hide resolved
peer/test_utils.go Outdated Show resolved Hide resolved
Ononiwu Maureen added 3 commits May 8, 2024 11:57
In this function `createTestPeer` is changed to
`createTestPeerWithChannel`. This is useful in coming commits where we
decouple the process of creating test peer from the function.

Signed-off-by: Ononiwu Maureen <[email protected]>
The `createTestPeerWithChannel` function is made to return this newly
created struct and error.

This is useful because upcoming commits would require us returning more
objects from the function.

Signed-off-by: Ononiwu Maureen <[email protected]>
test_utils

Signed-off-by: Ononiwu Maureen <[email protected]>
peer/test_utils.go Outdated Show resolved Hide resolved
Signed-off-by: Ononiwu Maureen <[email protected]>
Copy link
Collaborator

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

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

nice!

@lightninglabs-deploy
Copy link

@Chinwendu20, remember to re-request review from reviewers when ready

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants