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

Straightforwardly fixes a few minor copy bugs and adds a small fuzz util #5572

Conversation

davidporter-id-au
Copy link
Member

@davidporter-id-au davidporter-id-au commented Jan 1, 2024

What changed?

  • Adds the library github.com/google/gofuzz.
  • Adds a small wrapper for some repo-level conventions we may wish to follow by default - notably determinitism and logging the seed value
  • Adds some probably fairly low value but still easy to test copy functions as a demonstration of value.

Justification & intent

The problem I am trying to solve here is: How can we ensure that testdata is kept up-to-date and in-sync with the changing functions.

A canonical example is idl mapping, where a mapper for Protobuf generated type and it's common/types equivalent need to be kept in sync as the fields evolve and additional fields and substructs are added. Added test-data will continue to pass tests, but may silently omit new fields or not handle nil values safely as assumptions about what data must be present correctly.

Adding a 'fuzz' or generator for data makes such tests relatively easy: A round-trip test for a serialiser with generated code will easily spot missed values and generated code with occasional nils will ensure safe nil handling before deep-reaching into subfields.

Comparison vs alternatives

This is certainly not the only way to solve this problem: There are several obvious other ways to solve this:

a) straightforward reflection on existing testdata to ensure all fields are present with some kind of linter (rejected: Requires inventing a kind of DSL to specify optional fields in lots of scenarios where structs only sometimes exist, significant maintenance overhead)
b) The native golang security fuzzer available on testing.F (rejected because more adverserial than the problem I am trying to solve and computationally quite expensive to have it build a corpus of known inputs.
c) property based testing such as the stdlib testing/quick (rejected because the API is quite rigid and it's virtually impossible to use it to create nested substructures without adherence to the Generate() api and seems to completely not work with protobuf generated types (with their private fields)

result.Input = make([]byte, len(sourceInfo.Input))
copy(result.Input, sourceInfo.Input)
}
if sourceInfo.Control != nil {
Copy link
Member

Choose a reason for hiding this comment

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

I checked the Control field a few weeks ago to see why/where it is used and couldn't find anything explanatory. Do you know why we carry over this Control field?

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 have zero idea

Copy link
Member

Choose a reason for hiding this comment

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

I tried to figure it out a while ago too :|
I think the answer is somewhere in git history, but I didn't find anything understandable.

service/history/execution/mutable_state_util_test.go Outdated Show resolved Hide resolved
common/testing/testdatagen/persistence.go Outdated Show resolved Hide resolved
// skips the majority of difficult to generate values
// for the sake of simplicity in testing. Use it with the fuzz.Funcs(...) generation function
func GenHistoryEvent(o *types.HistoryEvent, c fuzz.Continue) {
t1 := int64(1704127933)
Copy link
Member

Choose a reason for hiding this comment

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

maybe something more understandable at a glance?

Suggested change
t1 := int64(1704127933)
t1 := MustParse(DateOnly, "2024-01-01").Unix()

@@ -328,6 +328,7 @@ func CopyWorkflowExecutionInfo(sourceInfo *persistence.WorkflowExecutionInfo) *p
ParentDomainID: sourceInfo.ParentDomainID,
ParentWorkflowID: sourceInfo.ParentWorkflowID,
ParentRunID: sourceInfo.ParentRunID,
IsCron: sourceInfo.IsCron,
Copy link
Member

Choose a reason for hiding this comment

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

bleh. I really need to try to finish a "this struct must be completely filled out" linter...

Copy link
Member

Choose a reason for hiding this comment

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

linter or unit test?
one option could be to write tests using cmp.Diff and pass source object fully populated. to make it future proof, test can also validate all the public fields in the source object tree is non-nil.

Copy link
Member Author

@davidporter-id-au davidporter-id-au Jan 18, 2024

Choose a reason for hiding this comment

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

That's fundamentally what I'm looking to enable with the generator here - the filling out completely thing.

As Steven mentions, an alternative would be some kind of linter which checks for unfilled / nil substructs or subfields. I worry though that that's a somewhat more intrusive / homebrewed solution requiring some annotation thing we come up with.

@coveralls
Copy link

coveralls commented Jan 11, 2024

Pull Request Test Coverage Report for Build 018e129e-e76b-458d-8d72-096f650c58ca

Details

  • 15 of 15 (100.0%) changed or added relevant lines in 1 file are covered.
  • 93 unchanged lines in 17 files lost coverage.
  • Overall coverage increased (+0.1%) to 63.344%

Files with Coverage Reduction New Missed Lines %
common/persistence/sql/sqlplugin/mysql/db.go 2 79.49%
common/persistence/sql/sqlplugin/mysql/task.go 2 73.68%
common/task/fifo_task_scheduler.go 2 85.57%
common/task/parallel_task_processor.go 2 93.06%
common/task/weighted_round_robin_task_scheduler.go 2 89.05%
common/util.go 2 91.69%
service/matching/db.go 2 73.23%
service/matching/matcher.go 2 90.72%
common/log/tag/tags.go 3 50.18%
common/persistence/nosql/nosqlplugin/cassandra/workflow.go 3 63.03%
Totals Coverage Status
Change from base Build 018e1161-98f3-4f26-8b26-8603b46078b8: 0.1%
Covered Lines: 92916
Relevant Lines: 146684

💛 - Coveralls

@davidporter-id-au davidporter-id-au force-pushed the bugfix/adding-some-missing-coverage-to-copy-utils branch from 2833306 to 64311a3 Compare March 5, 2024 23:09
Copy link

codecov bot commented Mar 5, 2024

Codecov Report

Merging #5572 (64311a3) into master (55ff29b) will increase coverage by 0.13%.
The diff coverage is 100.00%.

❗ Current head 64311a3 differs from pull request most recent head c9461a5. Consider uploading reports for the commit c9461a5 to get more accurate results

Additional details and impacted files
Files Coverage Δ
service/history/execution/mutable_state_util.go 71.97% <100.00%> (+44.17%) ⬆️

... and 4 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 55ff29b...c9461a5. Read the comment docs.

@davidporter-id-au davidporter-id-au enabled auto-merge (squash) March 6, 2024 07:17
@davidporter-id-au davidporter-id-au merged commit 71a196c into cadence-workflow:master Mar 6, 2024
18 checks passed
ketsiambaku pushed a commit to ketsiambaku/cadence that referenced this pull request Mar 6, 2024
…til (cadence-workflow#5572)

- Adds the library github.com/google/gofuzz.
- Adds a small wrapper for some repo-level conventions we may wish to follow by default - notably determinitism and logging the seed value
- Adds some probably fairly low value but still easy to test copy functions as a demonstration of value.
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.

5 participants