Skip to content

Commit

Permalink
Add state transition of document test
Browse files Browse the repository at this point in the history
  • Loading branch information
krapie committed Mar 13, 2023
1 parent 7b7b270 commit b831fff
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 8 deletions.
8 changes: 8 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ var (
// this client.
ErrDocumentNotAttached = errors.New("document is not attached")

// ErrDocumentNotDetached occurs when the given document is not detached from
// this client.
ErrDocumentNotDetached = errors.New("document is not detached")

// ErrUnsupportedWatchResponseType occurs when the given WatchResponseType
// is not supported.
ErrUnsupportedWatchResponseType = errors.New("unsupported watch response type")
Expand Down Expand Up @@ -246,6 +250,10 @@ func (c *Client) Attach(ctx context.Context, doc *document.Document) error {
return ErrClientNotActivated
}

if doc.Status() != document.StatusDetached {
return ErrDocumentNotDetached
}

doc.SetActor(c.id)

pbChangePack, err := converter.ToChangePack(doc.CreateChangePack())
Expand Down
30 changes: 23 additions & 7 deletions server/backend/database/client_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ const (
ClientActivated = "activated"
)

// Below are statuses of the document.
const (
documentAttached = "attached"
documentDetached = "detached"
DocumentAttached = "attached"
DocumentDetached = "detached"
DocumentRemoved = "removed"
)

// ClientDocInfo is a structure representing information of the document
Expand Down Expand Up @@ -101,12 +103,12 @@ func (i *ClientInfo) AttachDocument(docID types.ID) error {
i.Documents = make(map[types.ID]*ClientDocInfo)
}

if i.hasDocument(docID) && i.Documents[docID].Status == documentAttached {
if i.hasDocument(docID) && i.Documents[docID].Status == DocumentAttached {
return ErrDocumentAlreadyAttached
}

i.Documents[docID] = &ClientDocInfo{
Status: documentAttached,
Status: DocumentAttached,
ServerSeq: 0,
ClientSeq: 0,
}
Expand All @@ -121,7 +123,21 @@ func (i *ClientInfo) DetachDocument(docID types.ID) error {
return err
}

i.Documents[docID].Status = documentDetached
i.Documents[docID].Status = DocumentDetached
i.Documents[docID].ClientSeq = 0
i.Documents[docID].ServerSeq = 0
i.UpdatedAt = time.Now()

return nil
}

// RemoveDocument removes the given document from this client.
func (i *ClientInfo) RemoveDocument(docID types.ID) error {
if err := i.EnsureDocumentAttached(docID); err != nil {
return err
}

i.Documents[docID].Status = DocumentRemoved
i.Documents[docID].ClientSeq = 0
i.Documents[docID].ServerSeq = 0
i.UpdatedAt = time.Now()
Expand All @@ -135,7 +151,7 @@ func (i *ClientInfo) IsAttached(docID types.ID) (bool, error) {
return false, ErrDocumentNeverAttached
}

return i.Documents[docID].Status == documentAttached, nil
return i.Documents[docID].Status == DocumentAttached, nil
}

// Checkpoint returns the checkpoint of the given document.
Expand Down Expand Up @@ -170,7 +186,7 @@ func (i *ClientInfo) EnsureDocumentAttached(docID types.ID) error {
return ErrClientNotActivated
}

if !i.hasDocument(docID) || i.Documents[docID].Status == documentDetached {
if !i.hasDocument(docID) || i.Documents[docID].Status == DocumentDetached {
return ErrDocumentNotAttached
}

Expand Down
6 changes: 6 additions & 0 deletions server/backend/database/mongo/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,19 @@ func TestClient(t *testing.T) {
pack := doc.CreateChangePack()

// Set removed_at in docInfo and store changes
assert.NoError(t, clientInfo.RemoveDocument(docInfo.ID))
err = cli.CreateChangeInfos(ctx, dummyProjectID, docInfo, 0, pack.Changes, true)
assert.NoError(t, err)

// Check whether removed_at is set in docInfo
docInfo, err = cli.FindDocInfoByID(ctx, dummyProjectID, docInfo.ID)
assert.NoError(t, err)
assert.NotEqual(t, time.Time{}, docInfo.RemovedAt)

// Check whether DocumentRemoved status is set in clientInfo
clientInfo, err := cli.FindClientInfoByID(ctx, dummyProjectID, clientInfo.ID)
assert.NoError(t, err)
assert.NotEqual(t, database.DocumentRemoved, clientInfo.Documents[docInfo.ID].Status)
})

t.Run("reuse same key to create docInfo test ", func(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion server/rpc/yorkie_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ func (s *yorkieServer) RemoveDocument(
return nil, err
}

if err := clientInfo.DetachDocument(docInfo.ID); err != nil {
if err := clientInfo.RemoveDocument(docInfo.ID); err != nil {
return nil, err
}

Expand Down
33 changes: 33 additions & 0 deletions test/integration/document_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,4 +326,37 @@ func TestDocument(t *testing.T) {
assert.Equal(t, d1.Status(), document.StatusRemoved)
assert.Equal(t, d2.Status(), document.StatusRemoved)
})

// State transition of document
// ┌──────────┐ Attach ┌──────────┐ Remove ┌─────────┐
// │ Detached ├───────►│ Attached ├───────►│ Removed │
// └──────────┘ └─┬─┬──────┘ └─────────┘
// ▲ │ │ ▲
// └───────────┘ └─────┘
// Detach PushPull
t.Run("document state transition test", func(t *testing.T) {
ctx := context.Background()
cli, err := client.Dial(defaultServer.RPCAddr())
assert.NoError(t, err)
assert.NoError(t, cli.Activate(ctx))
defer func() {
assert.NoError(t, cli.Close())
}()

// 01. abnormal behavior on detached state
d1 := document.New(key.Key(helper.TestDocKey(t)))
assert.ErrorIs(t, cli.Detach(ctx, d1), client.ErrDocumentNotAttached)
assert.ErrorIs(t, cli.Sync(ctx, d1.Key()), client.ErrDocumentNotAttached)
assert.ErrorIs(t, cli.Remove(ctx, d1), client.ErrDocumentNotAttached)

// 02. abnormal behavior on attached state
assert.NoError(t, cli.Attach(ctx, d1))
assert.ErrorIs(t, cli.Attach(ctx, d1), client.ErrDocumentNotDetached)

// 03. abnormal behavior on removed state
assert.NoError(t, cli.Remove(ctx, d1))
assert.ErrorIs(t, cli.Remove(ctx, d1), client.ErrDocumentNotAttached)
assert.ErrorIs(t, cli.Sync(ctx, d1.Key()), client.ErrDocumentNotAttached)
assert.ErrorIs(t, cli.Detach(ctx, d1), client.ErrDocumentNotAttached)
})
}

0 comments on commit b831fff

Please sign in to comment.