diff --git a/acltree/acltree.go b/acltree/acltree.go index 1e0e3e00..b7a677a3 100644 --- a/acltree/acltree.go +++ b/acltree/acltree.go @@ -85,6 +85,7 @@ func BuildACLTree( return nil, err } aclTree.removeOrphans() + t.SetHeads(aclTree.Heads()) return aclTree, nil } diff --git a/acltree/acltree_test.go b/acltree/acltree_test.go index 163c47e2..8039e0b8 100644 --- a/acltree/acltree_test.go +++ b/acltree/acltree_test.go @@ -99,6 +99,56 @@ func TestACLTree_UserJoinUpdate_Append(t *testing.T) { assert.Equal(t, changeIds, []string{"A.1.1", "A.1.2", "B.1.1", "B.1.2", "B.1.3", "A.1.4"}) } +func TestACLTree_UserJoinUpdate_Rebuild(t *testing.T) { + thr, err := threadbuilder.NewThreadBuilderWithTestName("userjoinexampleupdate.yml") + if err != nil { + t.Fatal(err) + } + keychain := thr.GetKeychain() + accountData := &account.AccountData{ + Identity: keychain.GetIdentity("A"), + SignKey: keychain.SigningKeys["A"], + EncKey: keychain.EncryptionKeys["A"], + } + listener := &mockListener{} + tree, err := BuildACLTree(thr, accountData, listener) + if err != nil { + t.Fatalf("should Build acl ACLState without err: %v", err) + } + rawChanges := thr.GetUpdates("rebuild") + var changes []*Change + for _, ch := range rawChanges { + newCh, err := NewFromRawChange(ch) + if err != nil { + t.Fatalf("should be able to create change from raw: %v", err) + } + changes = append(changes, newCh) + } + + res, err := tree.AddChanges(changes...) + assert.Equal(t, res.Summary, AddResultSummaryRebuild) + + aclState := tree.ACLState() + aId := keychain.GeneratedIdentities["A"] + bId := keychain.GeneratedIdentities["B"] + cId := keychain.GeneratedIdentities["C"] + dId := keychain.GeneratedIdentities["D"] + + assert.Equal(t, aclState.identity, aId) + assert.Equal(t, aclState.userStates[aId].Permissions, pb.ACLChange_Admin) + assert.Equal(t, aclState.userStates[bId].Permissions, pb.ACLChange_Writer) + assert.Equal(t, aclState.userStates[cId].Permissions, pb.ACLChange_Reader) + assert.Equal(t, aclState.userStates[dId].Permissions, pb.ACLChange_Writer) + + var changeIds []string + + tree.Iterate(func(c *Change) (isContinue bool) { + changeIds = append(changeIds, c.Id) + return true + }) + assert.Equal(t, changeIds, []string{"A.1.1", "A.1.2", "B.1.1", "B.1.2", "A.1.4"}) +} + func TestACLTree_UserRemoveBuild(t *testing.T) { thr, err := threadbuilder.NewThreadBuilderWithTestName("userremoveexample.yml") if err != nil { diff --git a/acltree/treeiterator.go b/acltree/treeiterator.go index addcf307..19a20095 100644 --- a/acltree/treeiterator.go +++ b/acltree/treeiterator.go @@ -91,7 +91,15 @@ func (i *iterator) iterateLin(c *Change) bool { break } } - i.breakpoint = c + if len(c.Next) == 0 && len(c.PreviousIds) <= 1 { + if !i.f(c) { + return false + } + i.doneMap[c] = struct{}{} + } else { + i.breakpoint = c + } + return true } diff --git a/testutils/yamltests/userjoinexampleupdate.yml b/testutils/yamltests/userjoinexampleupdate.yml index 0dca174a..c3916cc6 100644 --- a/testutils/yamltests/userjoinexampleupdate.yml +++ b/testutils/yamltests/userjoinexampleupdate.yml @@ -133,3 +133,19 @@ updates: baseSnapshot: A.1.1 aclHeads: [ B.1.1 ] treeHeads: [ B.1.3 ] + - useCase: rebuild + changes: + - id: A.1.4 + identity: A + aclChanges: + - userAdd: + identity: D + permission: writer + encryptionKey: key.Enc.D + encryptedReadKeys: [ key.Read.1 ] + readKey: key.Read.1 + graph: + - id: A.1.4 + baseSnapshot: A.1.1 + aclHeads: [ A.1.1 ] + treeHeads: [ A.1.1 ]