-
Notifications
You must be signed in to change notification settings - Fork 53
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
test(i): Refactor tests to avoid asserting policyIDs #3171
base: develop
Are you sure you want to change the base?
test(i): Refactor tests to avoid asserting policyIDs #3171
Conversation
f1b0e4b
to
9c92c3e
Compare
tests/integration/acp/demo_test.go
Outdated
testUtils.SchemaUpdate{ | ||
Schema: ` | ||
type Users1 @policy( | ||
id: "%policyID%", | ||
resource: "users" | ||
) { | ||
name: String | ||
age: Int | ||
} | ||
|
||
type User2 @policy( | ||
id: "%policyID%", | ||
resource: "users" | ||
) { | ||
name: String | ||
age: Int | ||
} | ||
|
||
type User3 @policy( | ||
id: "%policyID%", | ||
resource: "users" | ||
) { | ||
name: String | ||
age: Int | ||
} | ||
`, | ||
|
||
PolicyIDs: immutable.Some([]int{0, 0, 1}), |
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.
suggestion: Having an index of the policyIDs is an nice addition. However, I find that this pattern is not very intuitive. Maybe if we made this a bit more generic it could even be useful for other dynamic assignments. My suggestion would be to change PolicyIDs
in SchemaUpdate
to a Replace
field that holds a map[string]any
. The outcome would give us something like this:
testUtils.SchemaUpdate{
Schema: `
type Users1 @policy(
id: "policy_0",
resource: "users"
) {
name: String
age: Int
}
type User2 @policy(
id: "policy_0",
resource: "users"
) {
name: String
age: Int
}
type User3 @policy(
id: "policy_1",
resource: "users"
) {
name: String
age: Int
}
`,
Replace: immutable.Some(map[string]any{
"policy_0": NewPolicyIndex(0),
"policy_1": NewPolicyIndex(1),
}),
}
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.
While I do like the flexibility of the high-level suggestion, might be interesting to see if the usage with the util function NewPolicyIndex(0)
is nicer (i am unsure atm).
Brainstorming a bit here, so the Replace
command will do all the replacing and handle "all substitution" types (like fetching policyIDs at Index x y z, or anything else in the future), for which we would need to define all these new index types? like one for policy and one for each other substitution types, etc?
But I guess I see the benefits are more than the cons above.
If others are happy I can try to move to this proposed approach
@sourcenetwork/database-team Would be nice to hear prefs others have
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 which we would need to define all these new index types
It's just a switch statement in the replace logic. We already have the NewFooIndex
functions for docIDs and soon CIDs. One of the switch items could even be string
to be able to substitute a manually defined 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.
I'd like to propose using Go templates as an alternative approach. It would make our schema definitions more readable and maintainable.
Many developers are already familiar with native Go template syntax. We can easily extend it with custom template functions for our specific needs.
Here's a simple example:
testUtils.SchemaUpdate{
Schema: `
type User1 @policy(
id: "{{.Policy0}}",
resource: "users"
) {
name: String
age: Int
}
type User2 @policy(
id: "{{.Policy0}}",
resource: "users"
) {
name: String
age: Int
}
type User3 @policy(
id: "{{.Policy1}}",
resource: "users"
) {
name: String
age: Int
}
`,
TemplateData: map[string]string{
"Policy0": NewPolicyIndex(0),
"Policy1": NewPolicyIndex(1),
},
}
We can even do some perversions with it (I'm not advocating):
testUtils.SchemaUpdate{
Schema: `
{{- define "userType" -}}
type {{.Name}} @policy(
id: "{{.PolicyID}}",
resource: "users"
) {
name: String
age: Int
}
{{- end -}}
{{template "userType" dict "Name" "User1" "PolicyID" (policyIndex 0)}}
{{template "userType" dict "Name" "User2" "PolicyID" (policyIndex 0)}}
{{template "userType" dict "Name" "User3" "PolicyID" (policyIndex 1)}}
`,
TemplateFuncs: template.FuncMap{
"policyIndex": func(i int) string {
return fmt.Sprintf("policy_%d", i)
},
"dict": func(values ...any) (map[string]any, error) {
if len(values)%2 != 0 {
return nil, errors.New("dict requires pairs")
}
dict := make(map[string]any, len(values)/2)
for i := 0; i < len(values); i += 2 {
key, ok := values[i].(string)
if !ok {
return nil, errors.New("dict keys must be strings")
}
dict[key] = values[i+1]
}
return dict, nil
},
},
}
It doesn't look very straightforward, at least not to the level we want to stick to in out tests.
It will just give us a lot more room for creativity in the future.
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.
What is "policy_0"
in your suggestion @islamaliev ?
TemplateData: map[string]string{
"Policy0": "policy_0",
"Policy1": "policy_1",
},
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.
well, it can be NewPolicyIndex(0)
or whatever else we decide.
I will update my proposal to make it complete.
// age: Int | ||
// } | ||
// ``` | ||
PolicyIDs immutable.Option[[]int] |
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.
suggestion: I don't think this being immutable.Option
adds anything besides complexity - there appears to be no behavioural differences between immutable.None
and an empty slice.
Same goes for Fred's suggestion about decoupling this from policyID
.
policyIDsAddedSoFar := len(s.policyIDs) | ||
// Expand the policyIDs slice once, so we can minimize how many times we need to expaind it. | ||
// We use the maximum nodeID provided to make sure policyIDs slice can accomodate upto that nodeID. | ||
if policyIDsAddedSoFar <= maxNodeID { |
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.
nitpick: would prefer if len(s.policyIDs) <= maxNodeID
as the variable doesn't add any clarity.
tests/integration/acp/demo_test.go
Outdated
testUtils.SchemaUpdate{ | ||
Schema: ` | ||
type Users1 @policy( | ||
id: "%policyID%", | ||
resource: "users" | ||
) { | ||
name: String | ||
age: Int | ||
} | ||
|
||
type User2 @policy( | ||
id: "%policyID%", | ||
resource: "users" | ||
) { | ||
name: String | ||
age: Int | ||
} | ||
|
||
type User3 @policy( | ||
id: "%policyID%", | ||
resource: "users" | ||
) { | ||
name: String | ||
age: Int | ||
} | ||
`, | ||
|
||
PolicyIDs: immutable.Some([]int{0, 0, 1}), |
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'd like to propose using Go templates as an alternative approach. It would make our schema definitions more readable and maintainable.
Many developers are already familiar with native Go template syntax. We can easily extend it with custom template functions for our specific needs.
Here's a simple example:
testUtils.SchemaUpdate{
Schema: `
type User1 @policy(
id: "{{.Policy0}}",
resource: "users"
) {
name: String
age: Int
}
type User2 @policy(
id: "{{.Policy0}}",
resource: "users"
) {
name: String
age: Int
}
type User3 @policy(
id: "{{.Policy1}}",
resource: "users"
) {
name: String
age: Int
}
`,
TemplateData: map[string]string{
"Policy0": NewPolicyIndex(0),
"Policy1": NewPolicyIndex(1),
},
}
We can even do some perversions with it (I'm not advocating):
testUtils.SchemaUpdate{
Schema: `
{{- define "userType" -}}
type {{.Name}} @policy(
id: "{{.PolicyID}}",
resource: "users"
) {
name: String
age: Int
}
{{- end -}}
{{template "userType" dict "Name" "User1" "PolicyID" (policyIndex 0)}}
{{template "userType" dict "Name" "User2" "PolicyID" (policyIndex 0)}}
{{template "userType" dict "Name" "User3" "PolicyID" (policyIndex 1)}}
`,
TemplateFuncs: template.FuncMap{
"policyIndex": func(i int) string {
return fmt.Sprintf("policy_%d", i)
},
"dict": func(values ...any) (map[string]any, error) {
if len(values)%2 != 0 {
return nil, errors.New("dict requires pairs")
}
dict := make(map[string]any, len(values)/2)
for i := 0; i < len(values); i += 2 {
key, ok := values[i].(string)
if !ok {
return nil, errors.New("dict keys must be strings")
}
dict[key] = values[i+1]
}
return dict, nil
},
},
}
It doesn't look very straightforward, at least not to the level we want to stick to in out tests.
It will just give us a lot more room for creativity in the future.
Accepting @fredcarle's suggestion to make it a more generic So we have: testUtils.SchemaUpdate{
Schema: `
type User1 @policy(
id: "{{.Policy0}}",
resource: "users"
) {
name: String
age: Int
}
type User2 @policy(
id: "{{.Policy0}}",
resource: "users"
) {
name: String
age: Int
}
type User3 @policy(
id: "{{.Policy1}}",
resource: "users"
) {
name: String
age: Int
}
`,
Replace: map[string]any{
"Policy0": NewPolicyIndex(0),
"Policy1": NewPolicyIndex(1),
},
} |
9c92c3e
to
11aeff5
Compare
- Just assert policyID is non-empty for PolicyID - Make PolicyID index substitution easier with `UpdateSchema` - Optional if we still want to do exact assertions
Note: the demo tests will be reverted after draft approval
11aeff5
to
87a211f
Compare
Relevant issue(s)
Resolves #3070
Description
Problem:
PolicyIDs will be unstable for the next little while and we want to avoid depending on them and having to change and maintain them overtime.
Solution in this PR:
Made it so that
AddPolicy
a action doesn't need to assert the exactpolicyID
anymore, it is optional we can still do so for some edge cases if we want but don't have to.Introduced a
PolicyIDs
attribute onSchemaUpdate
action as an optional list arg which makes it easier to substitute/embed PolicyIDs without depending on the exact policyIDs, the action will sub the policyIDs into the schema string where place holder labels ("%policyID%") are at, without us using explicit policy identifiers.Note:
Example:
Consider we have two policies that are added resulting in the following policyIDs:
On a Schema string like (before transformation):
The Schema that will be loaded will be this modified one:
For reviewers:
How has this been tested?