ソースを参照

完成state所有封装

yjp 3 年 前
コミット
51c50185ba
3 ファイル変更178 行追加15 行削除
  1. 23 0
      state/dto.go
  2. 20 5
      state/state.go
  3. 135 10
      test/state_test.go

+ 23 - 0
state/dto.go

@@ -18,3 +18,26 @@ type GetStateBulkItem struct {
 	Data string `json:"data"`
 	Etag string `json:"etag"`
 }
+
+const (
+	TransactionUpsert = "upsert"
+	TransactionDelete = "delete"
+)
+
+type TransactionRequest struct {
+	Operations []TransactionOperation `json:"operations"`
+	MetaData   map[string]string      `json:"metadata,omitempty"`
+}
+
+type TransactionOperation struct {
+	Operation string                      `json:"operation"`
+	Request   TransactionOperationRequest `json:"request"`
+}
+
+type TransactionOperationRequest struct {
+	Key      string            `json:"key"`
+	Value    string            `json:"value"`
+	Etag     string            `json:"etag,omitempty"`
+	MetaData map[string]string `json:"metadata,omitempty"`
+	Options  map[string]string `json:"options,omitempty"`
+}

+ 20 - 5
state/state.go

@@ -8,10 +8,11 @@ import (
 )
 
 const (
-	saveUrlFormat    = "http://localhost:%d/v1.0/state/%s"
-	getUrlFormat     = "http://localhost:%d/v1.0/state/%s/%s"
-	getBulkUrlFormat = "http://localhost:%d/v1.0/state/%s/bulk"
-	deleteUrlFormat  = "http://localhost:%d/v1.0/state/%s/%s"
+	saveUrlFormat        = "http://localhost:%d/v1.0/state/%s"
+	getUrlFormat         = "http://localhost:%d/v1.0/state/%s/%s"
+	getBulkUrlFormat     = "http://localhost:%d/v1.0/state/%s/bulk"
+	deleteUrlFormat      = "http://localhost:%d/v1.0/state/%s/%s"
+	transactionUrlFormat = "http://localhost:%d/v1.0/state/%s/transaction"
 )
 
 type API struct {
@@ -114,6 +115,20 @@ func (api *API) DeleteState(storeName string, key string, queryParams map[string
 	return nil
 }
 
-func (api *API) Transaction() {
+func (api *API) Transaction(storeName string, request TransactionRequest) error {
+	transactionUrl := fmt.Sprintf(transactionUrlFormat, api.port, storeName)
 
+	resp, err := api.client.R().
+		SetHeader("Content-Type", "application/json").
+		SetBody(request).
+		Post(transactionUrl)
+	if err != nil {
+		return err
+	}
+
+	if resp.IsError() {
+		return fmt.Errorf("Status %d: %s\n", resp.StatusCode(), resp.Body())
+	}
+
+	return nil
 }

+ 135 - 10
test/state_test.go

@@ -13,7 +13,48 @@ const (
 	stateStoreName = "dapr_api"
 )
 
-func TestState(t *testing.T) {
+func TestStateSaveAndGet(t *testing.T) {
+	api := state.NewAPI(httpPort, 10*time.Second)
+	defer state.DestroyAPI(api)
+
+	key := utils.SimpleUUID()
+	value := utils.SimpleUUID()
+
+	err := api.SaveState(stateStoreName, []state.SaveStateRequest{
+		{
+			Key:   key,
+			Value: value,
+		},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var getValue string
+	etag, err := api.GetState(stateStoreName, key, nil, &getValue)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assert.NotEmpty(t, etag, "etag为空")
+	assert.Equal(t, value, getValue, "value不一致")
+
+	err = api.DeleteState(stateStoreName, key, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	getValue = ""
+	etag, err = api.GetState(stateStoreName, key, nil, &getValue)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assert.Empty(t, etag, "etag不为空")
+	assert.Empty(t, getValue, "value不为空")
+}
+
+func TestStateGetBulk(t *testing.T) {
 	api := state.NewAPI(httpPort, 10*time.Second)
 	defer state.DestroyAPI(api)
 
@@ -36,15 +77,6 @@ func TestState(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	var getValue string
-	etag, err := api.GetState(stateStoreName, key1, nil, &getValue)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	assert.NotEmpty(t, etag, "etag为空")
-	assert.Equal(t, value1, getValue, "value不一致")
-
 	getStateBulkItems, err := api.GetStateBulk(stateStoreName, nil, state.GetStateBulkRequest{
 		Keys:        []string{key1, key2},
 		Parallelism: 1,
@@ -94,3 +126,96 @@ func TestState(t *testing.T) {
 		assert.Empty(t, getStateBulkItem.Data, "获取到的data不为空")
 	}
 }
+
+func TestTransaction(t *testing.T) {
+	api := state.NewAPI(httpPort, 10*time.Second)
+	defer state.DestroyAPI(api)
+
+	key1 := utils.SimpleUUID()
+	value1 := utils.SimpleUUID()
+	key2 := utils.SimpleUUID()
+	value2 := utils.SimpleUUID()
+
+	err := api.Transaction(stateStoreName, state.TransactionRequest{
+		Operations: []state.TransactionOperation{
+			{
+				Operation: state.TransactionUpsert,
+				Request: state.TransactionOperationRequest{
+					Key:   key1,
+					Value: value1,
+				},
+			},
+			{
+				Operation: state.TransactionUpsert,
+				Request: state.TransactionOperationRequest{
+					Key:   key2,
+					Value: value2,
+				},
+			},
+		},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	getStateBulkItems, err := api.GetStateBulk(stateStoreName, nil, state.GetStateBulkRequest{
+		Keys:        []string{key1, key2},
+		Parallelism: 1,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assert.Equal(t, 2, len(getStateBulkItems), "获取到的state数量不正确")
+
+	for _, getStateBulkItem := range getStateBulkItems {
+		assert.NotEmpty(t, getStateBulkItem.Etag, "etag为空")
+
+		if getStateBulkItem.Key != key1 && getStateBulkItem.Key != key2 {
+			t.Fatal("批量获取到的key错误")
+		}
+
+		if getStateBulkItem.Key == key1 {
+			assert.Equal(t, value1, getStateBulkItem.Data, "value不一致")
+		}
+
+		if getStateBulkItem.Key == key2 {
+			assert.Equal(t, value2, getStateBulkItem.Data, "value不一致")
+		}
+	}
+
+	err = api.Transaction(stateStoreName, state.TransactionRequest{
+		Operations: []state.TransactionOperation{
+			{
+				Operation: state.TransactionDelete,
+				Request: state.TransactionOperationRequest{
+					Key:   key1,
+					Value: value1,
+				},
+			},
+			{
+				Operation: state.TransactionDelete,
+				Request: state.TransactionOperationRequest{
+					Key:   key2,
+					Value: value2,
+				},
+			},
+		},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	getStateBulkItems, err = api.GetStateBulk(stateStoreName, nil, state.GetStateBulkRequest{
+		Keys:        []string{key1, key2},
+		Parallelism: 1,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, getStateBulkItem := range getStateBulkItems {
+		assert.Empty(t, getStateBulkItem.Etag, "获取到的etag不为空")
+		assert.Empty(t, getStateBulkItem.Data, "获取到的data不为空")
+	}
+}