Adds core query template tests to the state store.

This commit is contained in:
James Phillips 2016-03-02 20:54:46 -08:00
parent 328d138466
commit 897ab0d5c7
2 changed files with 294 additions and 1 deletions

View File

@ -130,7 +130,7 @@ func (s *StateStore) preparedQuerySetTxn(tx *memdb.Txn, idx uint64, query *struc
} }
other := toPreparedQuery(wrapped) other := toPreparedQuery(wrapped)
if other != nil && (existing == nil || existing.ID != other.ID) { if other != nil && (existing == nil || existing.ID != other.ID) {
return fmt.Errorf("name '%s' aliases an existing query template name", query.Name) return fmt.Errorf("a query template with an empty name already exists")
} }
} }

View File

@ -232,10 +232,186 @@ func TestStateStore_PreparedQuerySet_PreparedQueryGet(t *testing.T) {
} }
} }
// Try to register a template that squats on the existing query's name.
{
evil := &structs.PreparedQuery{
ID: testUUID(),
Name: query.Name,
Template: structs.QueryTemplateOptions{
Type: structs.QueryTemplateTypeNamePrefixMatch,
},
Service: structs.ServiceQuery{
Service: "redis",
},
}
err := s.PreparedQuerySet(8, evil)
if err == nil || !strings.Contains(err.Error(), "aliases an existing query name") {
t.Fatalf("bad: %v", err)
}
// Sanity check to make sure it's not there.
idx, actual, err := s.PreparedQueryGet(evil.ID)
if err != nil {
t.Fatalf("err: %s", err)
}
if idx != 6 {
t.Fatalf("bad index: %d", idx)
}
if actual != nil {
t.Fatalf("bad: %v", actual)
}
}
// Index is not updated if nothing is saved. // Index is not updated if nothing is saved.
if idx := s.maxIndex("prepared-queries"); idx != 6 { if idx := s.maxIndex("prepared-queries"); idx != 6 {
t.Fatalf("bad index: %d", idx) t.Fatalf("bad index: %d", idx)
} }
// Turn the query into a template with an empty name.
query.Name = ""
query.Template = structs.QueryTemplateOptions{
Type: structs.QueryTemplateTypeNamePrefixMatch,
}
if err := s.PreparedQuerySet(9, query); err != nil {
t.Fatalf("err: %s", err)
}
// Make sure the index got updated.
if idx := s.maxIndex("prepared-queries"); idx != 9 {
t.Fatalf("bad index: %d", idx)
}
// Read it back and verify the data was updated as well as the index.
expected.Name = ""
expected.Template = structs.QueryTemplateOptions{
Type: structs.QueryTemplateTypeNamePrefixMatch,
}
expected.ModifyIndex = 9
idx, actual, err = s.PreparedQueryGet(query.ID)
if err != nil {
t.Fatalf("err: %s", err)
}
if idx != 9 {
t.Fatalf("bad index: %d", idx)
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %v", actual)
}
// Try to register a template that squats on the empty prefix.
{
evil := &structs.PreparedQuery{
ID: testUUID(),
Name: "",
Template: structs.QueryTemplateOptions{
Type: structs.QueryTemplateTypeNamePrefixMatch,
},
Service: structs.ServiceQuery{
Service: "redis",
},
}
err := s.PreparedQuerySet(10, evil)
if err == nil || !strings.Contains(err.Error(), "query template with an empty name already exists") {
t.Fatalf("bad: %v", err)
}
// Sanity check to make sure it's not there.
idx, actual, err := s.PreparedQueryGet(evil.ID)
if err != nil {
t.Fatalf("err: %s", err)
}
if idx != 9 {
t.Fatalf("bad index: %d", idx)
}
if actual != nil {
t.Fatalf("bad: %v", actual)
}
}
// Give the query template a name.
query.Name = "prefix"
if err := s.PreparedQuerySet(11, query); err != nil {
t.Fatalf("err: %s", err)
}
// Make sure the index got updated.
if idx := s.maxIndex("prepared-queries"); idx != 11 {
t.Fatalf("bad index: %d", idx)
}
// Read it back and verify the data was updated as well as the index.
expected.Name = "prefix"
expected.ModifyIndex = 11
idx, actual, err = s.PreparedQueryGet(query.ID)
if err != nil {
t.Fatalf("err: %s", err)
}
if idx != 11 {
t.Fatalf("bad index: %d", idx)
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %v", actual)
}
// Try to register a template that squats on the prefix.
{
evil := &structs.PreparedQuery{
ID: testUUID(),
Name: "prefix",
Template: structs.QueryTemplateOptions{
Type: structs.QueryTemplateTypeNamePrefixMatch,
},
Service: structs.ServiceQuery{
Service: "redis",
},
}
err := s.PreparedQuerySet(12, evil)
if err == nil || !strings.Contains(err.Error(), "aliases an existing query name") {
t.Fatalf("bad: %v", err)
}
// Sanity check to make sure it's not there.
idx, actual, err := s.PreparedQueryGet(evil.ID)
if err != nil {
t.Fatalf("err: %s", err)
}
if idx != 11 {
t.Fatalf("bad index: %d", idx)
}
if actual != nil {
t.Fatalf("bad: %v", actual)
}
}
// Try to register a template that doesn't compile.
{
evil := &structs.PreparedQuery{
ID: testUUID(),
Name: "legit-prefix",
Template: structs.QueryTemplateOptions{
Type: structs.QueryTemplateTypeNamePrefixMatch,
},
Service: structs.ServiceQuery{
Service: "${nope",
},
}
err := s.PreparedQuerySet(13, evil)
if err == nil || !strings.Contains(err.Error(), "failed compiling template") {
t.Fatalf("bad: %v", err)
}
// Sanity check to make sure it's not there.
idx, actual, err := s.PreparedQueryGet(evil.ID)
if err != nil {
t.Fatalf("err: %s", err)
}
if idx != 11 {
t.Fatalf("bad index: %d", idx)
}
if actual != nil {
t.Fatalf("bad: %v", actual)
}
}
} }
func TestStateStore_PreparedQueryDelete(t *testing.T) { func TestStateStore_PreparedQueryDelete(t *testing.T) {
@ -417,6 +593,123 @@ func TestStateStore_PreparedQueryResolve(t *testing.T) {
if actual != nil { if actual != nil {
t.Fatalf("bad: %v", actual) t.Fatalf("bad: %v", actual)
} }
// Create two prepared query templates, one a longer prefix of the
// other.
tmpl1 := &structs.PreparedQuery{
ID: testUUID(),
Name: "prod-",
Template: structs.QueryTemplateOptions{
Type: structs.QueryTemplateTypeNamePrefixMatch,
},
Service: structs.ServiceQuery{
Service: "${name.suffix}",
},
}
if err := s.PreparedQuerySet(4, tmpl1); err != nil {
t.Fatalf("err: %s", err)
}
tmpl2 := &structs.PreparedQuery{
ID: testUUID(),
Name: "prod-redis",
Template: structs.QueryTemplateOptions{
Type: structs.QueryTemplateTypeNamePrefixMatch,
Regexp: "^prod-(.*)$",
},
Service: structs.ServiceQuery{
Service: "${match(1)}-master",
},
}
if err := s.PreparedQuerySet(5, tmpl2); err != nil {
t.Fatalf("err: %s", err)
}
// Resolve the less-specific prefix.
expected = &structs.PreparedQuery{
ID: tmpl1.ID,
Name: "prod-",
Template: structs.QueryTemplateOptions{
Type: structs.QueryTemplateTypeNamePrefixMatch,
},
Service: structs.ServiceQuery{
Service: "mongodb",
},
RaftIndex: structs.RaftIndex{
CreateIndex: 4,
ModifyIndex: 4,
},
}
idx, actual, err = s.PreparedQueryResolve("prod-mongodb")
if err != nil {
t.Fatalf("err: %s", err)
}
if idx != 5 {
t.Fatalf("bad index: %d", idx)
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %v", actual)
}
// Now resolve the more specific prefix.
expected = &structs.PreparedQuery{
ID: tmpl2.ID,
Name: "prod-redis",
Template: structs.QueryTemplateOptions{
Type: structs.QueryTemplateTypeNamePrefixMatch,
Regexp: "^prod-(.*)$",
},
Service: structs.ServiceQuery{
Service: "redis-foobar-master",
},
RaftIndex: structs.RaftIndex{
CreateIndex: 5,
ModifyIndex: 5,
},
}
idx, actual, err = s.PreparedQueryResolve("prod-redis-foobar")
if err != nil {
t.Fatalf("err: %s", err)
}
if idx != 5 {
t.Fatalf("bad index: %d", idx)
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %v", actual)
}
// Resolve an exact-match prefix. The output of this one doesn't match a
// sensical service name, but it still renders.
expected = &structs.PreparedQuery{
ID: tmpl1.ID,
Name: "prod-",
Template: structs.QueryTemplateOptions{
Type: structs.QueryTemplateTypeNamePrefixMatch,
},
Service: structs.ServiceQuery{
Service: "",
},
RaftIndex: structs.RaftIndex{
CreateIndex: 4,
ModifyIndex: 4,
},
}
idx, actual, err = s.PreparedQueryResolve("prod-")
if err != nil {
t.Fatalf("err: %s", err)
}
if idx != 5 {
t.Fatalf("bad index: %d", idx)
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %v", actual)
}
// Make sure you can't run a prepared query template by ID, since that
// makes no sense.
_, _, err = s.PreparedQueryResolve(tmpl1.ID)
if err == nil || !strings.Contains(err.Error(), "prepared query templates can only be resolved up by name") {
t.Fatalf("bad: %v", err)
}
} }
func TestStateStore_PreparedQueryList(t *testing.T) { func TestStateStore_PreparedQueryList(t *testing.T) {