-
Notifications
You must be signed in to change notification settings - Fork 198
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
Split blob writer code out of larger PR. #685
Split blob writer code out of larger PR. #685
Conversation
Signed-off-by: Cody Littley <[email protected]>
tools/traffic/test/mock_disperser.go
Outdated
@@ -0,0 +1,96 @@ | |||
package test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For mocks, you can enforce they adhere to some interface by doing something like this.
Ex. var _ clients.DisperserClient = (*mockDisperserClient)(nil)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat trick! I actually noticed a few similar lines in other files and was confused by them.
var previousData []byte | ||
|
||
for i := 0; i < 100; i++ { | ||
if rand.Float64() < errorProbability { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of testing the error cases probabilistically, why don't we have an explicit test case that tests the failures?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed this to non-random, it now generates an error every tenth cycle: if i%10 == 0
. Would you still like to se a stand alone unit test for the error case, or is this sufficient?
|
||
// These methods should be called exactly once per tick if there are no errors. | ||
// In the presence of errors, nothing should be passed to the unconfirmed key handler. | ||
assert.Equal(t, uint(i+1), disperserClient.DisperseCount) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also directly match if disperserClient.DisperseBlob
method has been called by disperserClient.AssertCalled(...)
or disperserClient.AssertNumberOfCalls(...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've switched over to your recommended style for mock objects.
tu.AssertEventuallyTrue(t, func() bool { | ||
lock.Lock() | ||
defer lock.Unlock() | ||
return int(disperserClient.DisperseCount) > i && int(unconfirmedKeyHandler.Count)+errorCount > i | ||
}, time.Second) | ||
|
||
// These methods should be called exactly once per tick if there are no errors. | ||
// In the presence of errors, nothing should be passed to the unconfirmed key handler. | ||
assert.Equal(t, uint(i+1), disperserClient.DisperseCount) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Timing/synchronizing with another goroutine might be tricky just using time. Does this reliably pass? How do you know if L101 will execute after disperser request has been made?
Maybe one thing we could do is make run
method public and run test against this method? That way we can assert expectations after the method returns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empirically, this was reliably passing (ran it in a loop a few thousand times). Primary reason why I was going through all the trouble of doing it in an attempt to put the tests in another directory without making methods public that shouldn't be public.
I understand your general concern though. I refactored this so that I don't rely on timing. As a result, the test files will end up being in the same package as the other files. Ugly to me, but it seems like a fairly normal practice in go.
Signed-off-by: Cody Littley <[email protected]>
Signed-off-by: Cody Littley <[email protected]>
Signed-off-by: Cody Littley <[email protected]>
Signed-off-by: Cody Littley <[email protected]>
Signed-off-by: Cody Littley <[email protected]>
Signed-off-by: Cody Littley <[email protected]>
Signed-off-by: Cody Littley <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm, left few more comments for you to consider before merging
disperser clients.DisperserClient | ||
|
||
// Unconfirmed keys are sent here. | ||
unconfirmedKeyHandler KeyHandler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have you considered passing unconfirmed keys to a channel instead and letting the caller handle it?
I think that's a common pattern in Go
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm willing to make this change, but since this modifies the API, would it be ok with you if I made this change in the next PR that will add the code that consumes the unconfirmed keys? It will cause some merge conflicts if I change this API in this PR.
tools/traffic/workers/blob_writer.go
Outdated
data := make([]byte, writer.config.DataSize) | ||
_, err := rand.Read(data) | ||
if err != nil { | ||
panic(fmt.Sprintf("unable to read random data: %s", err)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return an error instead of panicking?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
tools/traffic/workers/blob_writer.go
Outdated
}) | ||
if err != nil { | ||
writer.writeFailureMetric.Increment() | ||
writer.logger.Error("failed to send blob request", "err:", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: no :
postfix on labels
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
tools/traffic/workers/blob_writer.go
Outdated
} | ||
|
||
// sendRequest sends a blob to a disperser. | ||
func (writer *BlobWriter) sendRequest(data []byte) ([]byte /* key */, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could use a named return values if the returns values look ambiguous
...sendRequest(data []byte) (key []byte, err error)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, today I learned that syntax exists. :) Change made.
Signed-off-by: Cody Littley <[email protected]>
tools/traffic/workers/blob_writer.go
Outdated
"fmt" | ||
"github.com/Layr-Labs/eigenda/api/clients" | ||
"github.com/Layr-Labs/eigenda/encoding/utils/codec" | ||
config2 "github.com/Layr-Labs/eigenda/tools/traffic/config" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this alias needed? There seems no collision
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I blame my IDE, it automatically aliased this when I did an automatic refactor. 🙃
Fixed.
package workers | ||
|
||
// KeyHandler is an interface describing an object that can accept unconfirmed keys. | ||
type KeyHandler interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit abstract. Is it intended just for unconfirmed blobs? If so, it would be more readable to name these as BlobHandler/AddUncofirmedBlob etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will go away in the next PR when I implement a request from @ian-shim to use a channel to pass this data. I'm intentionally not changing it in this PR to reduce the number of merge conflicts in my feature branch.
// Start begins the blob writer goroutine. | ||
func (writer *BlobWriter) Start() { | ||
writer.waitGroup.Add(1) | ||
ticker := time.NewTicker(writer.config.WriteRequestInterval) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this support a write frequency like 0.2 blobs/sec?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. This is the period, aka the time in-between writes. If you set a period of 5 seconds, on average it will write 1/5 or 0.2 blobs per second.
Signed-off-by: Cody Littley <[email protected]>
Signed-off-by: Cody Littley <[email protected]>
Why are these changes needed?
This is code broken off from the larger PR #666
This branch contains the "BlobWriter", which manages the writing of blobs for the traffic generator.
Checks