-
Notifications
You must be signed in to change notification settings - Fork 1k
Conversation
Happy to make this a WIP. Could certainly use some more comments at least, if not more cases. |
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 think this is generally heading in a very useful direction! some issues with the equality checks in particular, though.
internal/gps/source_cache_test.go
Outdated
NewBranch(br).Pair(rev1), | ||
NewVersion(ver).Pair(rev2), | ||
} | ||
sort.Slice(versions, func(i, j int) bool { |
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.
1.7 still :(
internal/gps/source_cache_test.go
Outdated
} | ||
|
||
// compareManifests compares two manifests and reports differences as test errors. | ||
func compareManifests(t *testing.T, exp, got Manifest) { |
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: s/exp/want/
internal/gps/source_cache_test.go
Outdated
{ | ||
exp, got := exp.DependencyConstraints(), got.DependencyConstraints() | ||
if !projectConstraintsEqual(exp, got) { | ||
t.Errorf("expected constraints equal to %v but got %v", exp, got) |
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.
there's a (WNT):
, (GOT):
pattern used elsewhere in gps' tests. For consistency's sake, let's continue the pattern.
internal/gps/source_cache_test.go
Outdated
} | ||
sort.Strings(a.P.Imports) | ||
sort.Strings(b.P.Imports) | ||
if len(a.P.Imports) != len(b.P.Imports) { |
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, but let's sort after the length comparison so that we don't do an unnecessary sort.
internal/gps/source_cache_test.go
Outdated
|
||
// pairedVersionsEqual returns true if the PairedVersions have equal VersionTypes and Strings. | ||
func pairedVersionsEqual(a, b PairedVersion) bool { | ||
return a.Type() == b.Type() && a.String() == b.String() |
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.
constraint and version equality are something i've struggled with implementing a few times, as the rabbit hole goes pretty deep. i suppose that doing it with string-based comparisons is a good start, but if we're serious about this then it may entail some more digging in.
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 have some ideas to make this one more robust (at least we control all the implementing types, so worst case it is just cumbersome). I'll try to come up with some specific cases that break this approach first though.
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.
👍
it's been a while since i've attempted it, but IIRC, at least part of the problem was that the use cases i was trying to service had differing notions of equality. unfortunately, i can't remember what those use cases were - but, something to keep an eye out for when you look at this.
internal/gps/source_cache_test.go
Outdated
} | ||
|
||
switch b.Intersect(a) { | ||
case a, b: |
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 approach! sadly, i think this will fail if given range constraints from the semver lib, as those contain a slice and thus aren't comparable.
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.
panic: runtime error: comparing uncomparable type semver.rangeConstraint
👎
I'll take another stab at this.
internal/gps/source_cache_test.go
Outdated
} | ||
} | ||
|
||
// compareLocks compares two manifests and reports differences as test errors. |
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.
s/manifests/locks/
internal/gps/source_cache_test.go
Outdated
} | ||
|
||
// compareLocks compares two manifests and reports differences as test errors. | ||
func compareLocks(t *testing.T, exp, got Lock) { |
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.
why not reuse lock diffing for this?
for something this large, please break up later commits so it's easier for me to review the interdiff. |
Something went the wrong after the merge. 😢 |
Yeah, I was trying to preserve the history. Perhaps a proper rebase would have been less jarring. The individual commits are more readable this way, but I can squash it all into a single tidy commit or a new branch with a few separate commits - if either would be easier to review. Edit: Rebased |
Added a Notice that // Constraints compose the fmt.Stringer interface. This method is the
// bijective inverse of NewConstraint(): if a string yielded from this
// method is passed to NewConstraint(), a byte-identical instance of the
// original Constraint will be returend. |
Rebased |
codeclimate appears to have lost track of the branch |
|
||
// compareManifests compares two manifests and reports differences as test errors. | ||
func compareManifests(t *testing.T, want, got Manifest) { | ||
{ |
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.
huh. i didn't know you could do this. this is just to provide a block scope for want
and got
to be localized within, right?
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.
Yeah, it seemed cleaner than a bunch of 'want- Type' vars.
In general, I've found it handy to isolate small portions of longer functions that aren't candidates for entirely separate functions, if only to help readability regarding variable scope or to give some better scope to a comment than line breaks.
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.
equality semantics are the worst
if !ok { | ||
return false | ||
} | ||
return v == v2 |
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 one of those cases where we the definition of "equality" is really contextualized by how we use it. the default branch property on branchVersion
is only set correctly by sourceMgr
, not by anything that parses manifests. if we rely on this equals operator in the wrong place, then we have problems.
but, perhaps you intend that to be the difference between equals()
and Matches()
?
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.
The idea was to have a method for verifying the cache serialization strategy, since ==
and reflect.DeepEquals
are too strict. I have renamed the method to identical
, and expanded the doc.
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.
the default branch property on branchVersion is only set correctly by sourceMgr, not by anything that parses manifests.
The persistent cache handles this case (and hopefully all the other edge cases!).
internal/gps/constraints.go
Outdated
@@ -52,6 +52,9 @@ type Constraint interface { | |||
// It also forces Constraint to be a private/sealed interface, which is a | |||
// design goal of the system. | |||
typedString() string | |||
|
|||
// equals returns true if the constraints are logically equivalent. |
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.
Per the other notes in this review, this should be clearer about the semantics of the equality check.
@@ -269,3 +269,12 @@ func (vtu versionTypeUnion) Intersect(c Constraint) Constraint { | |||
|
|||
return none | |||
} | |||
|
|||
func (vtu versionTypeUnion) identical(c Constraint) bool { |
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 having second thoughts about this implementation....
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.
hahaha, yeah, the vtu is a nightmare
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.
Expanded to treat them as sets for which each element must have an identical member.
internal/gps/constraint_test.go
Outdated
a, b Constraint | ||
eq bool | ||
}{ | ||
{a: NewVersion("test"), b: NewVersion("test"), eq: true}, |
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 drop the keys here.
internal/gps/source_cache_test.go
Outdated
const root = "example.com/test" | ||
|
||
t.Run("info", func(t *testing.T) { | ||
newSemverConstraint := func(s string) Constraint { |
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.
Didn't you already define the same function in internal/gps/constraint_test.go
?
// Identical Constraints behave identically for all methods defined by the | ||
// interface. A Constraint is always identical to itself. | ||
// | ||
// Constraints serialized for caching are de-serialized into identical instances. |
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.
If the serialization process is stringifying, then this isn't true for branches, because of that default branch prop 😢
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.
It's more complicated than that. The encoding scheme is queued up for a future PR after this one (maybe the next, have to dig it out and rebase).
i think this is ready to merge, but i need those test greens first :/ |
good enough. in we go! 🎉 |
What does this do / why do we need it?
This change adds tests for
singleSourceCache
against the only current implementation,singleSourceCacheMemory
. They are more general than they need to be (e.g. equality funcs,cachedLock/Manifest
types), but this is in anticipation of being run against a persistentsingleSourceCache
as well for #431 (which can't rely on==
orreflect.DeepEquals
as liberally).