Skip to content

Commit

Permalink
Implemented safe update.
Browse files Browse the repository at this point in the history
  • Loading branch information
Justin Bailey committed Jun 5, 2017
1 parent 244d88a commit 156a2d6
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 15 deletions.
42 changes: 39 additions & 3 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ type Meta struct {
Plain map[string]string `json:"plain"`
Created time.Time `json:"created"`
LastModified time.Time `json:"last_modified"`
Version string `json:"version"`
Version string `json:"version,omitempty"`
}

// Record contains a plaintext 'Meta' object containing record metadata,
Expand Down Expand Up @@ -294,12 +294,19 @@ func (c *Client) Read(ctx context.Context, recordID string) (*Record, error) {
// Write writes a new encrypted record to the database. Returns the new record (with
// the original, unencrypted data)
func (c *Client) Write(ctx context.Context, recordType string, data *map[string]string, plain *map[string]string) (*Record, error) {
var plainMap map[string]string
if plain == nil {
plainMap = nil
} else {
plainMap = *plain
}

record := &Record{
Meta: Meta{
Type: recordType,
WriterID: c.Options.ClientID,
UserID: c.Options.ClientID, // for now
Plain: *plain,
Plain: plainMap,
},
Data: *data,
}
Expand All @@ -319,7 +326,7 @@ func (c *Client) Write(ctx context.Context, recordType string, data *map[string]
resp, err := c.rawCall(ctx, req, encryptedRecord)
if err != nil {
return nil, err
}
}

defer closeResp(resp)

Expand All @@ -330,6 +337,35 @@ func (c *Client) Write(ctx context.Context, recordType string, data *map[string]
return record, nil
}

// Updates a record, if the version field matches the
// version stored by E3DB.
//
// Returns HTTP 409 (Conflict) in error if the record cannot be updated.
func (c *Client) Update(ctx context.Context, record *Record) error {
encryptedRecord, err := c.encryptRecord(ctx, record)
if err != nil {
return err
}

buf := new(bytes.Buffer)
json.NewEncoder(buf).Encode(encryptedRecord)
u := fmt.Sprintf("%s/v1/storage/records/safe/%s/%s", c.apiURL(), url.QueryEscape(record.Meta.RecordID), url.QueryEscape(record.Meta.Version))
req, err := http.NewRequest("PUT", u, buf)
if err != nil {
return err
}

resp, err := c.rawCall(ctx, req, encryptedRecord)
if err != nil {
return err
}

defer closeResp(resp)

record.Meta = encryptedRecord.Meta
return nil
}

// Delete deletes a record given a record ID.
func (c *Client) Delete(ctx context.Context, recordID string) error {
u := fmt.Sprintf("%s/v1/storage/records/%s", c.apiURL(), url.QueryEscape(recordID))
Expand Down
81 changes: 69 additions & 12 deletions client_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"fmt"
"os"
"testing"
"net/http"

cli "github.com/jawher/mow.cli"
)
Expand Down Expand Up @@ -75,12 +76,13 @@ func TestGetClientInfo(t *testing.T) {
}

func TestWriteRead(t *testing.T) {
rec1 := client.NewRecord("test-data")
rec1.Data["message"] = "Hello, world!"
recordID, err := client.Write(context.Background(), rec1)
data := make(map[string]string)
data["message"] = "Hello, world!"
rec1, err := client.Write(context.Background(), "test-data", &data, nil)
if err != nil {
t.Fatal(err)
}
recordID := rec1.Meta.RecordID

rec2, err := client.Read(context.Background(), recordID)
if err != nil {
Expand All @@ -106,12 +108,13 @@ func TestWriteRead(t *testing.T) {

// TestWriteThenDelete should delete a record
func TestWriteThenDelete(t *testing.T) {
rec1 := client.NewRecord("test-data")
rec1.Data["message"] = "Hello, world!"
recordID, err := client.Write(context.Background(), rec1)
data := make(map[string]string)
data["message"] = "Hello, world!"
record, err := client.Write(context.Background(), "test-data", &data, nil)
if err != nil {
t.Fatal(err)
}
recordID := record.Meta.RecordID

err = client.Delete(context.Background(), recordID)
if err != nil {
Expand All @@ -120,9 +123,9 @@ func TestWriteThenDelete(t *testing.T) {
}

func TestShare(t *testing.T) {
rec1 := client.NewRecord("test-data")
rec1.Data["message"] = "Hello, world!"
_, err := client.Write(context.Background(), rec1)
data := make(map[string]string)
data["message"] = "Hello, world!"
_, err := client.Write(context.Background(), "test-data", &data, nil)
if err != nil {
t.Fatal(err)
}
Expand All @@ -135,9 +138,9 @@ func TestShare(t *testing.T) {

// TestShareThenUnshare should share then revoke sharing
func TestShareThenUnshare(t *testing.T) {
rec1 := client.NewRecord("test-share-data")
rec1.Data["message"] = "Hello, world!"
_, err := client.Write(context.Background(), rec1)
data := make(map[string]string)
data["message"] = "Hello, world!"
_, err := client.Write(context.Background(), "test-share-data", &data, nil)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -186,3 +189,57 @@ func TestEvents(t *testing.T) {
for range done {
}
}

func TestCounter(t *testing.T) {
data := make(map[string]string)
data["counter"] = "1"
rec1, err := client.Write(context.Background(), "test-data", &data, nil)
if err != nil {
t.Fatal(err)
}
recordID := rec1.Meta.RecordID

// Update w/ correct version
err = client.Update(context.Background(), rec1)
if err != nil {
t.Fatal(err)
}

rec1.Data["counter"] = "X"
rec1.Meta.Version = "6bc381c7-a41d-45ae-89aa-0890ad654673"
// should not update
err = client.Update(context.Background(), rec1)
if err == nil {
t.Fatal("Should not be able to update record with wrong version.")
}

if httpErr, ok := err.(*httpError); ok {
if httpErr.StatusCode != http.StatusConflict {
t.Fatal("Version conflict not reported.")
}
}

rec2, err := client.Read(context.Background(), recordID)
if err != nil {
t.Fatal(err)
}

if rec2.Data["counter"] != "1" {
t.Fatal("Counter had wrong value.")
}

rec2.Data["counter"] = "2"
err = client.Update(context.Background(), rec2)
if err != nil {
t.Fatal(err)
}

rec3, err := client.Read(context.Background(), recordID)
if err != nil {
t.Fatal(err)
}

if rec3.Data["counter"] != "2" {
t.Fatal("Counter had wrong value")
}
}

0 comments on commit 156a2d6

Please sign in to comment.