diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 15f27e31d4..8b44d824ff 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -4273,7 +4273,7 @@ paths: /namespaces/{ns}/tokens/{type}/pools: get: description: 'TODO: Description' - operationId: getTokenPools + operationId: getTokenPoolsByType parameters: - description: 'TODO: Description' in: path @@ -4600,7 +4600,7 @@ paths: /namespaces/{ns}/tokens/{type}/pools/{name}/accounts: get: description: 'TODO: Description' - operationId: getTokenAccounts + operationId: getTokenAccountsByPool parameters: - description: 'TODO: Description' in: path @@ -5148,7 +5148,7 @@ paths: /namespaces/{ns}/tokens/{type}/pools/{name}/transfers: get: description: 'TODO: Description' - operationId: getTokenTransfers + operationId: getTokenTransfersByPool parameters: - description: 'TODO: Description' in: path @@ -5267,13 +5267,30 @@ paths: schema: items: properties: - balance: {} - identity: + amount: {} + created: {} + from: type: string + key: + type: string + localId: {} + messageHash: {} poolProtocolId: type: string + protocolId: + type: string + to: + type: string tokenIndex: type: string + tx: + properties: + id: {} + type: + type: string + type: object + type: + type: string type: object type: array description: Success @@ -5500,6 +5517,406 @@ paths: description: Success default: description: "" + /namespaces/{ns}/tokens/accounts: + get: + description: 'TODO: Description' + operationId: getTokenAccounts + parameters: + - description: 'TODO: Description' + in: path + name: ns + required: true + schema: + example: default + type: string + - description: Server-side request timeout (millseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 120s + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: balance + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: identity + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: poolprotocolid + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: tokenindex + schema: + type: string + - description: Sort field. For multi-field sort use comma separated values (or + multiple query values) with '-' prefix for descending + in: query + name: sort + schema: + type: string + - description: Ascending sort order (overrides all fields in a multi-field sort) + in: query + name: ascending + schema: + type: string + - description: Descending sort order (overrides all fields in a multi-field + sort) + in: query + name: descending + schema: + type: string + - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk + operations' + in: query + name: skip + schema: + type: string + - description: 'The maximum number of records to return (max: 1,000)' + in: query + name: limit + schema: + example: "25" + type: string + - description: Return a total count as well as items (adds extra database processing) + in: query + name: count + schema: + type: string + responses: + "200": + content: + application/json: + schema: + items: + properties: + balance: {} + identity: + type: string + poolProtocolId: + type: string + tokenIndex: + type: string + type: object + type: array + description: Success + default: + description: "" + /namespaces/{ns}/tokens/connectors: + get: + description: 'TODO: Description' + operationId: getTokenConnectors + parameters: + - description: 'TODO: Description' + in: path + name: ns + required: true + schema: + example: default + type: string + - description: Server-side request timeout (millseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 120s + type: string + responses: + "200": + content: + application/json: + schema: + items: + properties: + name: + type: string + type: object + type: array + description: Success + default: + description: "" + /namespaces/{ns}/tokens/pools: + get: + description: 'TODO: Description' + operationId: getTokenPools + parameters: + - description: 'TODO: Description' + in: path + name: ns + required: true + schema: + example: default + type: string + - description: Server-side request timeout (millseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 120s + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: created + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: id + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: key + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: message + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: name + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: namespace + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: protocolid + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: symbol + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: type + schema: + type: string + - description: Sort field. For multi-field sort use comma separated values (or + multiple query values) with '-' prefix for descending + in: query + name: sort + schema: + type: string + - description: Ascending sort order (overrides all fields in a multi-field sort) + in: query + name: ascending + schema: + type: string + - description: Descending sort order (overrides all fields in a multi-field + sort) + in: query + name: descending + schema: + type: string + - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk + operations' + in: query + name: skip + schema: + type: string + - description: 'The maximum number of records to return (max: 1,000)' + in: query + name: limit + schema: + example: "25" + type: string + - description: Return a total count as well as items (adds extra database processing) + in: query + name: count + schema: + type: string + responses: + "200": + content: + application/json: + schema: + items: + properties: + config: + additionalProperties: {} + type: object + connector: + type: string + created: {} + id: {} + key: + type: string + message: {} + name: + type: string + namespace: + type: string + protocolId: + type: string + symbol: + type: string + tx: + properties: + id: {} + type: + type: string + type: object + type: + type: string + type: object + type: array + description: Success + default: + description: "" + /namespaces/{ns}/tokens/transfers: + get: + description: 'TODO: Description' + operationId: getTokenTransfers + parameters: + - description: 'TODO: Description' + in: path + name: ns + required: true + schema: + example: default + type: string + - description: Server-side request timeout (millseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 120s + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: amount + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: created + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: from + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: key + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: localid + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: messagehash + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: poolprotocolid + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: protocolid + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: to + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: tokenindex + schema: + type: string + - description: Sort field. For multi-field sort use comma separated values (or + multiple query values) with '-' prefix for descending + in: query + name: sort + schema: + type: string + - description: Ascending sort order (overrides all fields in a multi-field sort) + in: query + name: ascending + schema: + type: string + - description: Descending sort order (overrides all fields in a multi-field + sort) + in: query + name: descending + schema: + type: string + - description: 'The number of records to skip (max: 1,000). Unsuitable for bulk + operations' + in: query + name: skip + schema: + type: string + - description: 'The maximum number of records to return (max: 1,000)' + in: query + name: limit + schema: + example: "25" + type: string + - description: Return a total count as well as items (adds extra database processing) + in: query + name: count + schema: + type: string + responses: + "200": + content: + application/json: + schema: + items: + properties: + amount: {} + created: {} + from: + type: string + key: + type: string + localId: {} + messageHash: {} + poolProtocolId: + type: string + protocolId: + type: string + to: + type: string + tokenIndex: + type: string + tx: + properties: + id: {} + type: + type: string + type: object + type: + type: string + type: object + type: array + description: Success + default: + description: "" /namespaces/{ns}/transactions: get: description: 'TODO: Description' diff --git a/internal/apiserver/route_get_token_accounts.go b/internal/apiserver/route_get_token_accounts.go index 6e405a56a7..3e43229ced 100644 --- a/internal/apiserver/route_get_token_accounts.go +++ b/internal/apiserver/route_get_token_accounts.go @@ -28,12 +28,10 @@ import ( var getTokenAccounts = &oapispec.Route{ Name: "getTokenAccounts", - Path: "namespaces/{ns}/tokens/{type}/pools/{name}/accounts", + Path: "namespaces/{ns}/tokens/accounts", Method: http.MethodGet, PathParams: []*oapispec.PathParam{ {Name: "ns", ExampleFromConf: config.NamespacesDefault, Description: i18n.MsgTBD}, - {Name: "type", Description: i18n.MsgTBD}, - {Name: "name", Description: i18n.MsgTBD}, }, QueryParams: nil, FilterFactory: database.TokenAccountQueryFactory, @@ -42,6 +40,6 @@ var getTokenAccounts = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*fftypes.TokenAccount{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(r.Or.Assets().GetTokenAccounts(r.Ctx, r.PP["ns"], r.PP["type"], r.PP["name"], r.Filter)) + return filterResult(r.Or.Assets().GetTokenAccounts(r.Ctx, r.PP["ns"], r.Filter)) }, } diff --git a/internal/apiserver/route_get_token_accounts_by_pool.go b/internal/apiserver/route_get_token_accounts_by_pool.go new file mode 100644 index 0000000000..26eaa348e2 --- /dev/null +++ b/internal/apiserver/route_get_token_accounts_by_pool.go @@ -0,0 +1,47 @@ +// Copyright © 2021 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "net/http" + + "github.com/hyperledger/firefly/internal/config" + "github.com/hyperledger/firefly/internal/i18n" + "github.com/hyperledger/firefly/internal/oapispec" + "github.com/hyperledger/firefly/pkg/database" + "github.com/hyperledger/firefly/pkg/fftypes" +) + +var getTokenAccountsByPool = &oapispec.Route{ + Name: "getTokenAccountsByPool", + Path: "namespaces/{ns}/tokens/{type}/pools/{name}/accounts", + Method: http.MethodGet, + PathParams: []*oapispec.PathParam{ + {Name: "ns", ExampleFromConf: config.NamespacesDefault, Description: i18n.MsgTBD}, + {Name: "type", Description: i18n.MsgTBD}, + {Name: "name", Description: i18n.MsgTBD}, + }, + QueryParams: nil, + FilterFactory: database.TokenAccountQueryFactory, + Description: i18n.MsgTBD, + JSONInputValue: nil, + JSONOutputValue: func() interface{} { return []*fftypes.TokenAccount{} }, + JSONOutputCodes: []int{http.StatusOK}, + JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + return filterResult(r.Or.Assets().GetTokenAccountsByPool(r.Ctx, r.PP["ns"], r.PP["type"], r.PP["name"], r.Filter)) + }, +} diff --git a/internal/apiserver/route_get_token_accounts_by_pool_test.go b/internal/apiserver/route_get_token_accounts_by_pool_test.go new file mode 100644 index 0000000000..faa90d45c5 --- /dev/null +++ b/internal/apiserver/route_get_token_accounts_by_pool_test.go @@ -0,0 +1,42 @@ +// Copyright © 2021 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "net/http/httptest" + "testing" + + "github.com/hyperledger/firefly/mocks/assetmocks" + "github.com/hyperledger/firefly/pkg/fftypes" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestGetTokenAccountsByPool(t *testing.T) { + o, r := newTestAPIServer() + mam := &assetmocks.Manager{} + o.On("Assets").Return(mam) + req := httptest.NewRequest("GET", "/api/v1/namespaces/ns1/tokens/tok1/pools/pool1/accounts", nil) + req.Header.Set("Content-Type", "application/json; charset=utf-8") + res := httptest.NewRecorder() + + mam.On("GetTokenAccountsByPool", mock.Anything, "ns1", "tok1", "pool1", mock.Anything). + Return([]*fftypes.TokenAccount{}, nil, nil) + r.ServeHTTP(res, req) + + assert.Equal(t, 200, res.Result().StatusCode) +} diff --git a/internal/apiserver/route_get_token_accounts_test.go b/internal/apiserver/route_get_token_accounts_test.go index 58052137ca..6c481f25a6 100644 --- a/internal/apiserver/route_get_token_accounts_test.go +++ b/internal/apiserver/route_get_token_accounts_test.go @@ -30,11 +30,11 @@ func TestGetTokenAccounts(t *testing.T) { o, r := newTestAPIServer() mam := &assetmocks.Manager{} o.On("Assets").Return(mam) - req := httptest.NewRequest("GET", "/api/v1/namespaces/ns1/tokens/tok1/pools/pool1/accounts", nil) + req := httptest.NewRequest("GET", "/api/v1/namespaces/ns1/tokens/accounts", nil) req.Header.Set("Content-Type", "application/json; charset=utf-8") res := httptest.NewRecorder() - mam.On("GetTokenAccounts", mock.Anything, "ns1", "tok1", "pool1", mock.Anything). + mam.On("GetTokenAccounts", mock.Anything, "ns1", mock.Anything). Return([]*fftypes.TokenAccount{}, nil, nil) r.ServeHTTP(res, req) diff --git a/internal/apiserver/route_get_token_connectors.go b/internal/apiserver/route_get_token_connectors.go new file mode 100644 index 0000000000..ae1dcc8628 --- /dev/null +++ b/internal/apiserver/route_get_token_connectors.go @@ -0,0 +1,44 @@ +// Copyright © 2021 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "net/http" + + "github.com/hyperledger/firefly/internal/config" + "github.com/hyperledger/firefly/internal/i18n" + "github.com/hyperledger/firefly/internal/oapispec" + "github.com/hyperledger/firefly/pkg/fftypes" +) + +var getTokenConnectors = &oapispec.Route{ + Name: "getTokenConnectors", + Path: "namespaces/{ns}/tokens/connectors", + Method: http.MethodGet, + PathParams: []*oapispec.PathParam{ + {Name: "ns", ExampleFromConf: config.NamespacesDefault, Description: i18n.MsgTBD}, + }, + QueryParams: nil, + FilterFactory: nil, + Description: i18n.MsgTBD, + JSONInputValue: nil, + JSONOutputValue: func() interface{} { return []*fftypes.TokenConnector{} }, + JSONOutputCodes: []int{http.StatusOK}, + JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + return r.Or.Assets().GetTokenConnectors(r.Ctx, r.PP["ns"]) + }, +} diff --git a/internal/apiserver/route_get_token_connectors_test.go b/internal/apiserver/route_get_token_connectors_test.go new file mode 100644 index 0000000000..f19b426a57 --- /dev/null +++ b/internal/apiserver/route_get_token_connectors_test.go @@ -0,0 +1,42 @@ +// Copyright © 2021 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "net/http/httptest" + "testing" + + "github.com/hyperledger/firefly/mocks/assetmocks" + "github.com/hyperledger/firefly/pkg/fftypes" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestGetTokenConnectors(t *testing.T) { + o, r := newTestAPIServer() + mam := &assetmocks.Manager{} + o.On("Assets").Return(mam) + req := httptest.NewRequest("GET", "/api/v1/namespaces/ns1/tokens/connectors", nil) + req.Header.Set("Content-Type", "application/json; charset=utf-8") + res := httptest.NewRecorder() + + mam.On("GetTokenConnectors", mock.Anything, "ns1", mock.Anything). + Return([]*fftypes.TokenConnector{}, nil) + r.ServeHTTP(res, req) + + assert.Equal(t, 200, res.Result().StatusCode) +} diff --git a/internal/apiserver/route_get_token_pools.go b/internal/apiserver/route_get_token_pools.go index 0050ab8aef..d982c25f9b 100644 --- a/internal/apiserver/route_get_token_pools.go +++ b/internal/apiserver/route_get_token_pools.go @@ -28,11 +28,10 @@ import ( var getTokenPools = &oapispec.Route{ Name: "getTokenPools", - Path: "namespaces/{ns}/tokens/{type}/pools", + Path: "namespaces/{ns}/tokens/pools", Method: http.MethodGet, PathParams: []*oapispec.PathParam{ {Name: "ns", ExampleFromConf: config.NamespacesDefault, Description: i18n.MsgTBD}, - {Name: "type", Description: i18n.MsgTBD}, }, QueryParams: nil, FilterFactory: database.TokenPoolQueryFactory, @@ -41,6 +40,6 @@ var getTokenPools = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*fftypes.TokenPool{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(r.Or.Assets().GetTokenPools(r.Ctx, r.PP["ns"], r.PP["type"], r.Filter)) + return filterResult(r.Or.Assets().GetTokenPools(r.Ctx, r.PP["ns"], r.Filter)) }, } diff --git a/internal/apiserver/route_get_token_pools_by_type.go b/internal/apiserver/route_get_token_pools_by_type.go new file mode 100644 index 0000000000..22831fcf1d --- /dev/null +++ b/internal/apiserver/route_get_token_pools_by_type.go @@ -0,0 +1,46 @@ +// Copyright © 2021 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "net/http" + + "github.com/hyperledger/firefly/internal/config" + "github.com/hyperledger/firefly/internal/i18n" + "github.com/hyperledger/firefly/internal/oapispec" + "github.com/hyperledger/firefly/pkg/database" + "github.com/hyperledger/firefly/pkg/fftypes" +) + +var getTokenPoolsByType = &oapispec.Route{ + Name: "getTokenPoolsByType", + Path: "namespaces/{ns}/tokens/{type}/pools", + Method: http.MethodGet, + PathParams: []*oapispec.PathParam{ + {Name: "ns", ExampleFromConf: config.NamespacesDefault, Description: i18n.MsgTBD}, + {Name: "type", Description: i18n.MsgTBD}, + }, + QueryParams: nil, + FilterFactory: database.TokenPoolQueryFactory, + Description: i18n.MsgTBD, + JSONInputValue: nil, + JSONOutputValue: func() interface{} { return []*fftypes.TokenPool{} }, + JSONOutputCodes: []int{http.StatusOK}, + JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + return filterResult(r.Or.Assets().GetTokenPoolsByType(r.Ctx, r.PP["ns"], r.PP["type"], r.Filter)) + }, +} diff --git a/internal/apiserver/route_get_token_pools_by_type_test.go b/internal/apiserver/route_get_token_pools_by_type_test.go new file mode 100644 index 0000000000..083dbce79a --- /dev/null +++ b/internal/apiserver/route_get_token_pools_by_type_test.go @@ -0,0 +1,42 @@ +// Copyright © 2021 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "net/http/httptest" + "testing" + + "github.com/hyperledger/firefly/mocks/assetmocks" + "github.com/hyperledger/firefly/pkg/fftypes" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestGetTokenPoolsByType(t *testing.T) { + o, r := newTestAPIServer() + mam := &assetmocks.Manager{} + o.On("Assets").Return(mam) + req := httptest.NewRequest("GET", "/api/v1/namespaces/ns1/tokens/tok1/pools", nil) + req.Header.Set("Content-Type", "application/json; charset=utf-8") + res := httptest.NewRecorder() + + mam.On("GetTokenPoolsByType", mock.Anything, "ns1", "tok1", mock.Anything). + Return([]*fftypes.TokenPool{}, nil, nil) + r.ServeHTTP(res, req) + + assert.Equal(t, 200, res.Result().StatusCode) +} diff --git a/internal/apiserver/route_get_token_pools_test.go b/internal/apiserver/route_get_token_pools_test.go index 668fa47f4d..084bf33656 100644 --- a/internal/apiserver/route_get_token_pools_test.go +++ b/internal/apiserver/route_get_token_pools_test.go @@ -30,11 +30,11 @@ func TestGetTokenPools(t *testing.T) { o, r := newTestAPIServer() mam := &assetmocks.Manager{} o.On("Assets").Return(mam) - req := httptest.NewRequest("GET", "/api/v1/namespaces/ns1/tokens/tok1/pools", nil) + req := httptest.NewRequest("GET", "/api/v1/namespaces/ns1/tokens/pools", nil) req.Header.Set("Content-Type", "application/json; charset=utf-8") res := httptest.NewRecorder() - mam.On("GetTokenPools", mock.Anything, "ns1", "tok1", mock.Anything). + mam.On("GetTokenPools", mock.Anything, "ns1", mock.Anything). Return([]*fftypes.TokenPool{}, nil, nil) r.ServeHTTP(res, req) diff --git a/internal/apiserver/route_get_token_transfers.go b/internal/apiserver/route_get_token_transfers.go index d3b4bd8f3a..5ec1a59223 100644 --- a/internal/apiserver/route_get_token_transfers.go +++ b/internal/apiserver/route_get_token_transfers.go @@ -28,20 +28,18 @@ import ( var getTokenTransfers = &oapispec.Route{ Name: "getTokenTransfers", - Path: "namespaces/{ns}/tokens/{type}/pools/{name}/transfers", + Path: "namespaces/{ns}/tokens/transfers", Method: http.MethodGet, PathParams: []*oapispec.PathParam{ {Name: "ns", ExampleFromConf: config.NamespacesDefault, Description: i18n.MsgTBD}, - {Name: "type", Description: i18n.MsgTBD}, - {Name: "name", Description: i18n.MsgTBD}, }, QueryParams: nil, FilterFactory: database.TokenTransferQueryFactory, Description: i18n.MsgTBD, JSONInputValue: nil, - JSONOutputValue: func() interface{} { return []*fftypes.TokenAccount{} }, + JSONOutputValue: func() interface{} { return []*fftypes.TokenTransfer{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(r.Or.Assets().GetTokenTransfers(r.Ctx, r.PP["ns"], r.PP["type"], r.PP["name"], r.Filter)) + return filterResult(r.Or.Assets().GetTokenTransfers(r.Ctx, r.PP["ns"], r.Filter)) }, } diff --git a/internal/apiserver/route_get_token_transfers_by_pool.go b/internal/apiserver/route_get_token_transfers_by_pool.go new file mode 100644 index 0000000000..5eb57e2806 --- /dev/null +++ b/internal/apiserver/route_get_token_transfers_by_pool.go @@ -0,0 +1,47 @@ +// Copyright © 2021 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "net/http" + + "github.com/hyperledger/firefly/internal/config" + "github.com/hyperledger/firefly/internal/i18n" + "github.com/hyperledger/firefly/internal/oapispec" + "github.com/hyperledger/firefly/pkg/database" + "github.com/hyperledger/firefly/pkg/fftypes" +) + +var getTokenTransfersByPool = &oapispec.Route{ + Name: "getTokenTransfersByPool", + Path: "namespaces/{ns}/tokens/{type}/pools/{name}/transfers", + Method: http.MethodGet, + PathParams: []*oapispec.PathParam{ + {Name: "ns", ExampleFromConf: config.NamespacesDefault, Description: i18n.MsgTBD}, + {Name: "type", Description: i18n.MsgTBD}, + {Name: "name", Description: i18n.MsgTBD}, + }, + QueryParams: nil, + FilterFactory: database.TokenTransferQueryFactory, + Description: i18n.MsgTBD, + JSONInputValue: nil, + JSONOutputValue: func() interface{} { return []*fftypes.TokenTransfer{} }, + JSONOutputCodes: []int{http.StatusOK}, + JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + return filterResult(r.Or.Assets().GetTokenTransfersByPool(r.Ctx, r.PP["ns"], r.PP["type"], r.PP["name"], r.Filter)) + }, +} diff --git a/internal/apiserver/route_get_token_transfers_by_pool_test.go b/internal/apiserver/route_get_token_transfers_by_pool_test.go new file mode 100644 index 0000000000..4b11ce07a3 --- /dev/null +++ b/internal/apiserver/route_get_token_transfers_by_pool_test.go @@ -0,0 +1,42 @@ +// Copyright © 2021 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package apiserver + +import ( + "net/http/httptest" + "testing" + + "github.com/hyperledger/firefly/mocks/assetmocks" + "github.com/hyperledger/firefly/pkg/fftypes" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestGetTokenTransfersByPool(t *testing.T) { + o, r := newTestAPIServer() + mam := &assetmocks.Manager{} + o.On("Assets").Return(mam) + req := httptest.NewRequest("GET", "/api/v1/namespaces/ns1/tokens/tok1/pools/pool1/transfers", nil) + req.Header.Set("Content-Type", "application/json; charset=utf-8") + res := httptest.NewRecorder() + + mam.On("GetTokenTransfersByPool", mock.Anything, "ns1", "tok1", "pool1", mock.Anything). + Return([]*fftypes.TokenTransfer{}, nil, nil) + r.ServeHTTP(res, req) + + assert.Equal(t, 200, res.Result().StatusCode) +} diff --git a/internal/apiserver/route_get_token_transfers_test.go b/internal/apiserver/route_get_token_transfers_test.go index 2de66b163b..d1480cc13a 100644 --- a/internal/apiserver/route_get_token_transfers_test.go +++ b/internal/apiserver/route_get_token_transfers_test.go @@ -30,11 +30,11 @@ func TestGetTokenTransfers(t *testing.T) { o, r := newTestAPIServer() mam := &assetmocks.Manager{} o.On("Assets").Return(mam) - req := httptest.NewRequest("GET", "/api/v1/namespaces/ns1/tokens/tok1/pools/pool1/transfers", nil) + req := httptest.NewRequest("GET", "/api/v1/namespaces/ns1/tokens/transfers", nil) req.Header.Set("Content-Type", "application/json; charset=utf-8") res := httptest.NewRecorder() - mam.On("GetTokenTransfers", mock.Anything, "ns1", "tok1", "pool1", mock.Anything). + mam.On("GetTokenTransfers", mock.Anything, "ns1", mock.Anything). Return([]*fftypes.TokenTransfer{}, nil, nil) r.ServeHTTP(res, req) diff --git a/internal/apiserver/routes.go b/internal/apiserver/routes.go index 78bcc642d6..1ba4f56692 100644 --- a/internal/apiserver/routes.go +++ b/internal/apiserver/routes.go @@ -79,10 +79,14 @@ var routes = []*oapispec.Route{ postTokenPool, getTokenPools, + getTokenPoolsByType, getTokenPoolByName, getTokenAccounts, + getTokenAccountsByPool, getTokenTransfers, + getTokenTransfersByPool, postTokenMint, postTokenBurn, postTokenTransfer, + getTokenConnectors, } diff --git a/internal/assets/manager.go b/internal/assets/manager.go index dd3294f981..0c67694cd7 100644 --- a/internal/assets/manager.go +++ b/internal/assets/manager.go @@ -36,15 +36,19 @@ import ( type Manager interface { CreateTokenPool(ctx context.Context, ns, typeName string, pool *fftypes.TokenPool, waitConfirm bool) (*fftypes.TokenPool, error) - GetTokenPools(ctx context.Context, ns, typeName string, filter database.AndFilter) ([]*fftypes.TokenPool, *database.FilterResult, error) + GetTokenPools(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.TokenPool, *database.FilterResult, error) + GetTokenPoolsByType(ctx context.Context, ns, typeName string, filter database.AndFilter) ([]*fftypes.TokenPool, *database.FilterResult, error) GetTokenPool(ctx context.Context, ns, typeName, poolName string) (*fftypes.TokenPool, error) ValidateTokenPoolTx(ctx context.Context, pool *fftypes.TokenPool, protocolTxID string) error - GetTokenAccounts(ctx context.Context, ns, typeName, poolName string, filter database.AndFilter) ([]*fftypes.TokenAccount, *database.FilterResult, error) - GetTokenTransfers(ctx context.Context, ns, typeName, poolName string, filter database.AndFilter) ([]*fftypes.TokenTransfer, *database.FilterResult, error) + GetTokenAccounts(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.TokenAccount, *database.FilterResult, error) + GetTokenAccountsByPool(ctx context.Context, ns, typeName, poolName string, filter database.AndFilter) ([]*fftypes.TokenAccount, *database.FilterResult, error) + GetTokenTransfers(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.TokenTransfer, *database.FilterResult, error) + GetTokenTransfersByPool(ctx context.Context, ns, typeName, poolName string, filter database.AndFilter) ([]*fftypes.TokenTransfer, *database.FilterResult, error) NewTransfer(ns, typeName, poolName string, transfer *fftypes.TokenTransferInput) sysmessaging.MessageSender MintTokens(ctx context.Context, ns, typeName, poolName string, transfer *fftypes.TokenTransferInput, waitConfirm bool) (*fftypes.TokenTransfer, error) BurnTokens(ctx context.Context, ns, typeName, poolName string, transfer *fftypes.TokenTransferInput, waitConfirm bool) (*fftypes.TokenTransfer, error) TransferTokens(ctx context.Context, ns, typeName, poolName string, transfer *fftypes.TokenTransferInput, waitConfirm bool) (*fftypes.TokenTransfer, error) + GetTokenConnectors(ctx context.Context, ns string) ([]*fftypes.TokenConnector, error) // Bound token callbacks TokenPoolCreated(tk tokens.Plugin, pool *fftypes.TokenPool, protocolTxID string, additionalInfo fftypes.JSONObject) error @@ -102,7 +106,11 @@ func (am *assetManager) scopeNS(ns string, filter database.AndFilter) database.A return filter.Condition(filter.Builder().Eq("namespace", ns)) } -func (am *assetManager) GetTokenAccounts(ctx context.Context, ns, typeName, poolName string, filter database.AndFilter) ([]*fftypes.TokenAccount, *database.FilterResult, error) { +func (am *assetManager) GetTokenAccounts(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.TokenAccount, *database.FilterResult, error) { + return am.database.GetTokenAccounts(ctx, filter) +} + +func (am *assetManager) GetTokenAccountsByPool(ctx context.Context, ns, typeName, poolName string, filter database.AndFilter) ([]*fftypes.TokenAccount, *database.FilterResult, error) { pool, err := am.GetTokenPool(ctx, ns, typeName, poolName) if err != nil { return nil, nil, err @@ -110,6 +118,24 @@ func (am *assetManager) GetTokenAccounts(ctx context.Context, ns, typeName, pool return am.database.GetTokenAccounts(ctx, filter.Condition(filter.Builder().Eq("poolprotocolid", pool.ProtocolID))) } +func (am *assetManager) GetTokenConnectors(ctx context.Context, ns string) ([]*fftypes.TokenConnector, error) { + if err := fftypes.ValidateFFNameField(ctx, ns, "namespace"); err != nil { + return nil, err + } + + connectors := []*fftypes.TokenConnector{} + for token := range am.tokens { + connectors = append( + connectors, + &fftypes.TokenConnector{ + Name: token, + }, + ) + } + + return connectors, nil +} + func (am *assetManager) Start() error { return nil } diff --git a/internal/assets/manager_test.go b/internal/assets/manager_test.go index 1c75ee3adf..edce894b27 100644 --- a/internal/assets/manager_test.go +++ b/internal/assets/manager_test.go @@ -71,6 +71,18 @@ func TestGetTokenAccounts(t *testing.T) { am, cancel := newTestAssets(t) defer cancel() + mdi := am.database.(*databasemocks.Plugin) + fb := database.TokenAccountQueryFactory.NewFilter(context.Background()) + f := fb.And() + mdi.On("GetTokenAccounts", context.Background(), f).Return([]*fftypes.TokenAccount{}, nil, nil) + _, _, err := am.GetTokenAccounts(context.Background(), "ns1", f) + assert.NoError(t, err) +} + +func TestGetTokenAccountsByPool(t *testing.T) { + am, cancel := newTestAssets(t) + defer cancel() + pool := &fftypes.TokenPool{ ID: fftypes.NewUUID(), } @@ -79,11 +91,11 @@ func TestGetTokenAccounts(t *testing.T) { f := fb.And() mdi.On("GetTokenPool", context.Background(), "ns1", "test").Return(pool, nil) mdi.On("GetTokenAccounts", context.Background(), f).Return([]*fftypes.TokenAccount{}, nil, nil) - _, _, err := am.GetTokenAccounts(context.Background(), "ns1", "magic-tokens", "test", f) + _, _, err := am.GetTokenAccountsByPool(context.Background(), "ns1", "magic-tokens", "test", f) assert.NoError(t, err) } -func TestGetTokenAccountsBadPool(t *testing.T) { +func TestGetTokenAccountsByPoolBadPool(t *testing.T) { am, cancel := newTestAssets(t) defer cancel() @@ -91,6 +103,22 @@ func TestGetTokenAccountsBadPool(t *testing.T) { fb := database.TokenAccountQueryFactory.NewFilter(context.Background()) f := fb.And() mdi.On("GetTokenPool", context.Background(), "ns1", "test").Return(nil, fmt.Errorf("pop")) - _, _, err := am.GetTokenAccounts(context.Background(), "ns1", "magic-tokens", "test", f) + _, _, err := am.GetTokenAccountsByPool(context.Background(), "ns1", "magic-tokens", "test", f) assert.EqualError(t, err, "pop") } + +func TestGetTokenConnectors(t *testing.T) { + am, cancel := newTestAssets(t) + defer cancel() + + _, err := am.GetTokenConnectors(context.Background(), "ns1") + assert.NoError(t, err) +} + +func TestGetTokenConnectorsBadNamespace(t *testing.T) { + am, cancel := newTestAssets(t) + defer cancel() + + _, err := am.GetTokenConnectors(context.Background(), "") + assert.Regexp(t, "FF10131", err) +} diff --git a/internal/assets/token_pool.go b/internal/assets/token_pool.go index d8159a1181..90d7b6545e 100644 --- a/internal/assets/token_pool.go +++ b/internal/assets/token_pool.go @@ -118,7 +118,14 @@ func (am *assetManager) createTokenPoolWithID(ctx context.Context, id *fftypes.U return pool, plugin.CreateTokenPool(ctx, op.ID, pool) } -func (am *assetManager) GetTokenPools(ctx context.Context, ns string, typeName string, filter database.AndFilter) ([]*fftypes.TokenPool, *database.FilterResult, error) { +func (am *assetManager) GetTokenPools(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.TokenPool, *database.FilterResult, error) { + if err := fftypes.ValidateFFNameField(ctx, ns, "namespace"); err != nil { + return nil, nil, err + } + return am.database.GetTokenPools(ctx, am.scopeNS(ns, filter)) +} + +func (am *assetManager) GetTokenPoolsByType(ctx context.Context, ns string, typeName string, filter database.AndFilter) ([]*fftypes.TokenPool, *database.FilterResult, error) { if _, err := am.selectTokenPlugin(ctx, typeName); err != nil { return nil, nil, err } diff --git a/internal/assets/token_pool_test.go b/internal/assets/token_pool_test.go index feefcf8bda..9c1a0a560d 100644 --- a/internal/assets/token_pool_test.go +++ b/internal/assets/token_pool_test.go @@ -211,26 +211,49 @@ func TestGetTokenPools(t *testing.T) { fb := database.TokenPoolQueryFactory.NewFilter(context.Background()) f := fb.And(fb.Eq("id", u)) mdi.On("GetTokenPools", context.Background(), f).Return([]*fftypes.TokenPool{}, nil, nil) - _, _, err := am.GetTokenPools(context.Background(), "ns1", "magic-tokens", f) + _, _, err := am.GetTokenPools(context.Background(), "ns1", f) assert.NoError(t, err) } -func TestGetTokenPoolsBadPlugin(t *testing.T) { +func TestGetTokenPoolsBadNamespace(t *testing.T) { am, cancel := newTestAssets(t) defer cancel() - _, _, err := am.GetTokenPools(context.Background(), "", "", nil) + u := fftypes.NewUUID() + fb := database.TokenPoolQueryFactory.NewFilter(context.Background()) + f := fb.And(fb.Eq("id", u)) + _, _, err := am.GetTokenPools(context.Background(), "", f) + assert.Regexp(t, "FF10131", err) +} + +func TestGetTokenPoolsByType(t *testing.T) { + am, cancel := newTestAssets(t) + defer cancel() + u := fftypes.NewUUID() + mdi := am.database.(*databasemocks.Plugin) + fb := database.TokenPoolQueryFactory.NewFilter(context.Background()) + f := fb.And(fb.Eq("id", u)) + mdi.On("GetTokenPools", context.Background(), f).Return([]*fftypes.TokenPool{}, nil, nil) + _, _, err := am.GetTokenPoolsByType(context.Background(), "ns1", "magic-tokens", f) + assert.NoError(t, err) +} + +func TestGetTokenPoolsByTypeBadPlugin(t *testing.T) { + am, cancel := newTestAssets(t) + defer cancel() + + _, _, err := am.GetTokenPoolsByType(context.Background(), "", "", nil) assert.Regexp(t, "FF10272", err) } -func TestGetTokenPoolsBadNamespace(t *testing.T) { +func TestGetTokenPoolsByTypeBadNamespace(t *testing.T) { am, cancel := newTestAssets(t) defer cancel() u := fftypes.NewUUID() fb := database.TokenPoolQueryFactory.NewFilter(context.Background()) f := fb.And(fb.Eq("id", u)) - _, _, err := am.GetTokenPools(context.Background(), "", "magic-tokens", f) + _, _, err := am.GetTokenPoolsByType(context.Background(), "", "magic-tokens", f) assert.Regexp(t, "FF10131", err) } diff --git a/internal/assets/token_transfer.go b/internal/assets/token_transfer.go index 960cf911b6..5e7e0d86bc 100644 --- a/internal/assets/token_transfer.go +++ b/internal/assets/token_transfer.go @@ -33,7 +33,11 @@ func addTokenTransferInputs(op *fftypes.Operation, transfer *fftypes.TokenTransf } } -func (am *assetManager) GetTokenTransfers(ctx context.Context, ns, typeName, name string, filter database.AndFilter) ([]*fftypes.TokenTransfer, *database.FilterResult, error) { +func (am *assetManager) GetTokenTransfers(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.TokenTransfer, *database.FilterResult, error) { + return am.database.GetTokenTransfers(ctx, filter) +} + +func (am *assetManager) GetTokenTransfersByPool(ctx context.Context, ns, typeName, name string, filter database.AndFilter) ([]*fftypes.TokenTransfer, *database.FilterResult, error) { pool, err := am.GetTokenPool(ctx, ns, typeName, name) if err != nil { return nil, nil, err diff --git a/internal/assets/token_transfer_test.go b/internal/assets/token_transfer_test.go index e91baf176e..3018cce8d6 100644 --- a/internal/assets/token_transfer_test.go +++ b/internal/assets/token_transfer_test.go @@ -39,6 +39,18 @@ func TestGetTokenTransfers(t *testing.T) { am, cancel := newTestAssets(t) defer cancel() + mdi := am.database.(*databasemocks.Plugin) + fb := database.TokenTransferQueryFactory.NewFilter(context.Background()) + f := fb.And() + mdi.On("GetTokenTransfers", context.Background(), f).Return([]*fftypes.TokenTransfer{}, nil, nil) + _, _, err := am.GetTokenTransfers(context.Background(), "ns1", f) + assert.NoError(t, err) +} + +func TestGetTokenTransfersByPool(t *testing.T) { + am, cancel := newTestAssets(t) + defer cancel() + pool := &fftypes.TokenPool{ ID: fftypes.NewUUID(), } @@ -47,11 +59,11 @@ func TestGetTokenTransfers(t *testing.T) { f := fb.And() mdi.On("GetTokenPool", context.Background(), "ns1", "test").Return(pool, nil) mdi.On("GetTokenTransfers", context.Background(), f).Return([]*fftypes.TokenTransfer{}, nil, nil) - _, _, err := am.GetTokenTransfers(context.Background(), "ns1", "magic-tokens", "test", f) + _, _, err := am.GetTokenTransfersByPool(context.Background(), "ns1", "magic-tokens", "test", f) assert.NoError(t, err) } -func TestGetTokenTransfersBadPool(t *testing.T) { +func TestGetTokenTransfersByPoolBadPool(t *testing.T) { am, cancel := newTestAssets(t) defer cancel() @@ -59,11 +71,11 @@ func TestGetTokenTransfersBadPool(t *testing.T) { fb := database.TokenTransferQueryFactory.NewFilter(context.Background()) f := fb.And() mdi.On("GetTokenPool", context.Background(), "ns1", "test").Return(nil, fmt.Errorf("pop")) - _, _, err := am.GetTokenTransfers(context.Background(), "ns1", "magic-tokens", "test", f) + _, _, err := am.GetTokenTransfersByPool(context.Background(), "ns1", "magic-tokens", "test", f) assert.EqualError(t, err, "pop") } -func TestGetTokenTransfersNoPool(t *testing.T) { +func TestGetTokenTransfersByPoolNoPool(t *testing.T) { am, cancel := newTestAssets(t) defer cancel() @@ -71,7 +83,7 @@ func TestGetTokenTransfersNoPool(t *testing.T) { fb := database.TokenTransferQueryFactory.NewFilter(context.Background()) f := fb.And() mdi.On("GetTokenPool", context.Background(), "ns1", "test").Return(nil, nil) - _, _, err := am.GetTokenTransfers(context.Background(), "ns1", "magic-tokens", "test", f) + _, _, err := am.GetTokenTransfersByPool(context.Background(), "ns1", "magic-tokens", "test", f) assert.Regexp(t, "FF10109", err) } diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 7eabbba4a3..fd14c34022 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -324,13 +324,17 @@ func (or *orchestrator) initPlugins(ctx context.Context) (err error) { if or.tokens == nil { or.tokens = make(map[string]tokens.Plugin) - for i := 0; i < tokensConfig.ArraySize(); i++ { + tokensConfigArraySize := tokensConfig.ArraySize() + for i := 0; i < tokensConfigArraySize; i++ { prefix := tokensConfig.ArrayEntry(i) name := prefix.GetString(tokens.TokensConfigName) pluginName := prefix.GetString(tokens.TokensConfigPlugin) if name == "" { return i18n.NewError(ctx, i18n.MsgMissingTokensPluginConfig) } + if err = fftypes.ValidateFFNameField(ctx, name, "name"); err != nil { + return err + } if pluginName == "" { // Migration path for old config key // TODO: eventually make this fatal diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index cfcb6c5b2c..661899601a 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -335,6 +335,27 @@ func TestBadTokensPluginNoName(t *testing.T) { assert.Regexp(t, "FF10273", err) } +func TestBadTokensPluginInvalidName(t *testing.T) { + or := newTestOrchestrator() + tokensConfig = config.NewPluginConfig("tokens").Array() + tifactory.InitPrefix(tokensConfig) + tokensConfig.AddKnownKey(tokens.TokensConfigName, "!wrong") + tokensConfig.AddKnownKey(tokens.TokensConfigConnector, "text") + config.Set("tokens", []fftypes.JSONObject{{}}) + or.tokens = nil + or.mdi.On("GetConfigRecords", mock.Anything, mock.Anything, mock.Anything).Return([]*fftypes.ConfigRecord{}, nil, nil) + or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mii.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mps.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mdi.On("GetNamespace", mock.Anything, mock.Anything).Return(nil, nil) + or.mdi.On("UpsertNamespace", mock.Anything, mock.Anything, true).Return(nil) + ctx, cancelCtx := context.WithCancel(context.Background()) + err := or.Init(ctx, cancelCtx) + assert.Regexp(t, "FF10131.*'name'", err) +} + func TestBadTokensPluginNoType(t *testing.T) { or := newTestOrchestrator() tokensConfig = config.NewPluginConfig("tokens").Array() diff --git a/mocks/assetmocks/manager.go b/mocks/assetmocks/manager.go index 850689dd60..564d2e649c 100644 --- a/mocks/assetmocks/manager.go +++ b/mocks/assetmocks/manager.go @@ -66,8 +66,40 @@ func (_m *Manager) CreateTokenPool(ctx context.Context, ns string, typeName stri return r0, r1 } -// GetTokenAccounts provides a mock function with given fields: ctx, ns, typeName, poolName, filter -func (_m *Manager) GetTokenAccounts(ctx context.Context, ns string, typeName string, poolName string, filter database.AndFilter) ([]*fftypes.TokenAccount, *database.FilterResult, error) { +// GetTokenAccounts provides a mock function with given fields: ctx, ns, filter +func (_m *Manager) GetTokenAccounts(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.TokenAccount, *database.FilterResult, error) { + ret := _m.Called(ctx, ns, filter) + + var r0 []*fftypes.TokenAccount + if rf, ok := ret.Get(0).(func(context.Context, string, database.AndFilter) []*fftypes.TokenAccount); ok { + r0 = rf(ctx, ns, filter) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*fftypes.TokenAccount) + } + } + + var r1 *database.FilterResult + if rf, ok := ret.Get(1).(func(context.Context, string, database.AndFilter) *database.FilterResult); ok { + r1 = rf(ctx, ns, filter) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*database.FilterResult) + } + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, string, database.AndFilter) error); ok { + r2 = rf(ctx, ns, filter) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// GetTokenAccountsByPool provides a mock function with given fields: ctx, ns, typeName, poolName, filter +func (_m *Manager) GetTokenAccountsByPool(ctx context.Context, ns string, typeName string, poolName string, filter database.AndFilter) ([]*fftypes.TokenAccount, *database.FilterResult, error) { ret := _m.Called(ctx, ns, typeName, poolName, filter) var r0 []*fftypes.TokenAccount @@ -98,6 +130,29 @@ func (_m *Manager) GetTokenAccounts(ctx context.Context, ns string, typeName str return r0, r1, r2 } +// GetTokenConnectors provides a mock function with given fields: ctx, ns +func (_m *Manager) GetTokenConnectors(ctx context.Context, ns string) ([]*fftypes.TokenConnector, error) { + ret := _m.Called(ctx, ns) + + var r0 []*fftypes.TokenConnector + if rf, ok := ret.Get(0).(func(context.Context, string) []*fftypes.TokenConnector); ok { + r0 = rf(ctx, ns) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*fftypes.TokenConnector) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, ns) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetTokenPool provides a mock function with given fields: ctx, ns, typeName, poolName func (_m *Manager) GetTokenPool(ctx context.Context, ns string, typeName string, poolName string) (*fftypes.TokenPool, error) { ret := _m.Called(ctx, ns, typeName, poolName) @@ -121,8 +176,40 @@ func (_m *Manager) GetTokenPool(ctx context.Context, ns string, typeName string, return r0, r1 } -// GetTokenPools provides a mock function with given fields: ctx, ns, typeName, filter -func (_m *Manager) GetTokenPools(ctx context.Context, ns string, typeName string, filter database.AndFilter) ([]*fftypes.TokenPool, *database.FilterResult, error) { +// GetTokenPools provides a mock function with given fields: ctx, ns, filter +func (_m *Manager) GetTokenPools(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.TokenPool, *database.FilterResult, error) { + ret := _m.Called(ctx, ns, filter) + + var r0 []*fftypes.TokenPool + if rf, ok := ret.Get(0).(func(context.Context, string, database.AndFilter) []*fftypes.TokenPool); ok { + r0 = rf(ctx, ns, filter) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*fftypes.TokenPool) + } + } + + var r1 *database.FilterResult + if rf, ok := ret.Get(1).(func(context.Context, string, database.AndFilter) *database.FilterResult); ok { + r1 = rf(ctx, ns, filter) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*database.FilterResult) + } + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, string, database.AndFilter) error); ok { + r2 = rf(ctx, ns, filter) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// GetTokenPoolsByType provides a mock function with given fields: ctx, ns, typeName, filter +func (_m *Manager) GetTokenPoolsByType(ctx context.Context, ns string, typeName string, filter database.AndFilter) ([]*fftypes.TokenPool, *database.FilterResult, error) { ret := _m.Called(ctx, ns, typeName, filter) var r0 []*fftypes.TokenPool @@ -153,8 +240,40 @@ func (_m *Manager) GetTokenPools(ctx context.Context, ns string, typeName string return r0, r1, r2 } -// GetTokenTransfers provides a mock function with given fields: ctx, ns, typeName, poolName, filter -func (_m *Manager) GetTokenTransfers(ctx context.Context, ns string, typeName string, poolName string, filter database.AndFilter) ([]*fftypes.TokenTransfer, *database.FilterResult, error) { +// GetTokenTransfers provides a mock function with given fields: ctx, ns, filter +func (_m *Manager) GetTokenTransfers(ctx context.Context, ns string, filter database.AndFilter) ([]*fftypes.TokenTransfer, *database.FilterResult, error) { + ret := _m.Called(ctx, ns, filter) + + var r0 []*fftypes.TokenTransfer + if rf, ok := ret.Get(0).(func(context.Context, string, database.AndFilter) []*fftypes.TokenTransfer); ok { + r0 = rf(ctx, ns, filter) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*fftypes.TokenTransfer) + } + } + + var r1 *database.FilterResult + if rf, ok := ret.Get(1).(func(context.Context, string, database.AndFilter) *database.FilterResult); ok { + r1 = rf(ctx, ns, filter) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*database.FilterResult) + } + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, string, database.AndFilter) error); ok { + r2 = rf(ctx, ns, filter) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// GetTokenTransfersByPool provides a mock function with given fields: ctx, ns, typeName, poolName, filter +func (_m *Manager) GetTokenTransfersByPool(ctx context.Context, ns string, typeName string, poolName string, filter database.AndFilter) ([]*fftypes.TokenTransfer, *database.FilterResult, error) { ret := _m.Called(ctx, ns, typeName, poolName, filter) var r0 []*fftypes.TokenTransfer diff --git a/pkg/fftypes/tokenconnector.go b/pkg/fftypes/tokenconnector.go new file mode 100644 index 0000000000..282dec9591 --- /dev/null +++ b/pkg/fftypes/tokenconnector.go @@ -0,0 +1,21 @@ +// Copyright © 2021 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fftypes + +type TokenConnector struct { + Name string `json:"name,omitempty"` +}