From d616fa867c6d90f9c7e82ca1643a016424aff46d Mon Sep 17 00:00:00 2001 From: Alex Shorsher Date: Thu, 2 Jun 2022 17:36:21 -0400 Subject: [PATCH 01/33] Reorganize ns manager and orchestrator Update namespace manager to contain an orchestrator per namespace. Now, namespace manager will validate & get all plugins, validate all namespaces defined in configuration, and instantiate an orchestrator for each namespace. Orchestrator now receives the defined plugins for that orchestrator's namespace and instantiates the managers. This is a first pass - some items are still broken and need further work. Signed-off-by: Alex Shorsher --- internal/namespace/manager.go | 559 ++++++++++++++++++---- internal/orchestrator/orchestrator.go | 642 +++++--------------------- 2 files changed, 590 insertions(+), 611 deletions(-) diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index 4d7c4514c3..8748c56acd 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -21,47 +21,453 @@ import ( "fmt" "github.com/hyperledger/firefly-common/pkg/config" - "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly-common/pkg/i18n" "github.com/hyperledger/firefly-common/pkg/log" + "github.com/hyperledger/firefly/internal/adminevents" + "github.com/hyperledger/firefly/internal/blockchain/bifactory" "github.com/hyperledger/firefly/internal/coreconfig" "github.com/hyperledger/firefly/internal/coremsgs" - "github.com/hyperledger/firefly/pkg/blockchain" + "github.com/hyperledger/firefly/internal/database/difactory" + "github.com/hyperledger/firefly/internal/dataexchange/dxfactory" + "github.com/hyperledger/firefly/internal/identity/iifactory" + "github.com/hyperledger/firefly/internal/metrics" + "github.com/hyperledger/firefly/internal/orchestrator" + "github.com/hyperledger/firefly/internal/sharedstorage/ssfactory" + "github.com/hyperledger/firefly/internal/tokens/tifactory" "github.com/hyperledger/firefly/pkg/core" "github.com/hyperledger/firefly/pkg/database" - "github.com/hyperledger/firefly/pkg/dataexchange" - "github.com/hyperledger/firefly/pkg/sharedstorage" "github.com/hyperledger/firefly/pkg/tokens" ) +var ( + blockchainConfig = config.RootArray("plugins.blockchain") + tokensConfig = config.RootArray("plugins.tokens") + databaseConfig = config.RootArray("plugins.database") + sharedstorageConfig = config.RootArray("plugins.sharedstorage") + dataexchangeConfig = config.RootArray("plugins.dataexchange") + identityConfig = config.RootArray("plugins.identity") + // Deprecated configs + deprecatedTokensConfig = config.RootArray("tokens") + deprecatedBlockchainConfig = config.RootSection("blockchain") + deprecatedDatabaseConfig = config.RootSection("database") + deprecatedSharedStorageConfig = config.RootSection("sharedstorage") + deprecatedDataexchangeConfig = config.RootSection("dataexchange") +) + type Manager interface { // Init initializes the manager - Init(ctx context.Context, di database.Plugin) error + Init(ctx context.Context, cancelCtx context.CancelFunc) error +} + +//maybe add the orchestrator in this struct? +// mode?? +type namespace struct { + // not sure if we need config + config config.Section + multiparty bool + database orchestrator.DatabasePlugin + blockchain orchestrator.BlockchainPlugin + dataexchange orchestrator.DataexchangePlugin + sharedstorage orchestrator.SharedStoragePlugin + identity orchestrator.IdentityPlugin + tokens map[string]orchestrator.TokensPlugin } type namespaceManager struct { - ctx context.Context - nsConfig map[string]config.Section - bcPlugins map[string]blockchain.Plugin - dbPlugins map[string]database.Plugin - dxPlugins map[string]dataexchange.Plugin - ssPlugins map[string]sharedstorage.Plugin - tokensPlugins map[string]tokens.Plugin + ctx context.Context + cancelCtx context.CancelFunc + orchestrators map[string]orchestrator.Orchestrator + pluginNames map[string]bool + metrics metrics.Manager + blockchains map[string]orchestrator.BlockchainPlugin + identities map[string]orchestrator.IdentityPlugin + databases map[string]orchestrator.DatabasePlugin + sharedstorages map[string]orchestrator.SharedStoragePlugin + dataexchanges map[string]orchestrator.DataexchangePlugin + tokens map[string]orchestrator.TokensPlugin + database database.Plugin + adminEvents adminevents.Manager + namespaces map[string]namespace } -func NewNamespaceManager(ctx context.Context, bc map[string]blockchain.Plugin, db map[string]database.Plugin, dx map[string]dataexchange.Plugin, ss map[string]sharedstorage.Plugin, tokens map[string]tokens.Plugin) Manager { - nm := &namespaceManager{ - ctx: ctx, - nsConfig: buildNamespaceMap(ctx), - bcPlugins: bc, - dbPlugins: db, - dxPlugins: dx, - ssPlugins: ss, - tokensPlugins: tokens, - } +func NewNamespaceManager(withDefaults bool) Manager { + nm := &namespaceManager{} + + // Initialize the config on all the factories + bifactory.InitConfigDeprecated(deprecatedBlockchainConfig) + bifactory.InitConfig(blockchainConfig) + difactory.InitConfigDeprecated(deprecatedDatabaseConfig) + difactory.InitConfig(databaseConfig) + ssfactory.InitConfigDeprecated(deprecatedSharedStorageConfig) + ssfactory.InitConfig(sharedstorageConfig) + dxfactory.InitConfig(dataexchangeConfig) + dxfactory.InitConfigDeprecated(deprecatedDataexchangeConfig) + iifactory.InitConfig(identityConfig) + tifactory.InitConfigDeprecated(deprecatedTokensConfig) + tifactory.InitConfig(tokensConfig) + return nm } +func (nm *namespaceManager) Init(ctx context.Context, cancelCtx context.CancelFunc) (err error) { + nm.ctx = ctx + nm.cancelCtx = cancelCtx + + err = nm.getPlugins(ctx) + if err != nil { + return err + } + + nsConfig := buildNamespaceMap(ctx) + if err = nm.initNamespaces(ctx, nsConfig); err != nil { + return err + } + + // Start an orchestrator per namespace + if err = nm.initOrchestrators(ctx, cancelCtx); err != nil { + return err + } + + return err +} + +func (nm *namespaceManager) initOrchestrators(ctx context.Context, cancelCtx context.CancelFunc) (err error) { + for name, ns := range nm.namespaces { + //maybe export the namespace struct and have orchestrator take that as a parameter? + or := orchestrator.NewOrchestrator(ns.blockchain, ns.database, ns.sharedstorage, ns.dataexchange, ns.tokens, ns.identity, nm.metrics) + if err = or.Init(ctx, cancelCtx); err != nil { + return err + } + + if err = or.Start(); err != nil { + return err + } + nm.orchestrators[name] = or + } + + return err +} + +func (nm *namespaceManager) getPlugins(ctx context.Context) (err error) { + //TODO: combine plugin/config section into a struct? to help w/ plugin initialization in orchestrator + + nm.pluginNames = make(map[string]bool) + if nm.metrics == nil { + nm.metrics = metrics.NewMetricsManager(ctx) + } + + if nm.databases == nil { + nm.databases, err = nm.getDatabasePlugins(ctx) + if err != nil { + return err + } + } + + // Not really a plugin, but this has to be initialized here after the database (at least temporarily). + // Shortly after this step, namespaces will be synced to the database and will generate notifications to adminEvents. + if nm.adminEvents == nil { + nm.adminEvents = adminevents.NewAdminEventManager(ctx) + } + + if nm.identities == nil { + nm.identities, err = nm.getIdentityPlugins(ctx) + if err != nil { + return err + } + } + + if nm.blockchains == nil { + nm.blockchains, err = nm.getBlockchainPlugins(ctx) + if err != nil { + return err + } + } + + if nm.sharedstorages == nil { + nm.sharedstorages, err = nm.getSharedStoragePlugins(ctx) + if err != nil { + return err + } + } + + if nm.dataexchanges == nil { + nm.dataexchanges, err = nm.getDataExchangePlugins(ctx) + if err != nil { + return err + } + } + + if nm.tokens == nil { + nm.tokens, err = nm.getTokensPlugins(ctx) + if err != nil { + return err + } + } + + return nil +} + +func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[string]orchestrator.TokensPlugin, err error) { + plugins = make(map[string]orchestrator.TokensPlugin) + + tokensConfigArraySize := tokensConfig.ArraySize() + for i := 0; i < tokensConfigArraySize; i++ { + config := tokensConfig.ArrayEntry(i) + if err = nm.validatePluginConfig(ctx, config, "tokens"); err != nil { + return nil, err + } + + plugin, err := tifactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) + if err != nil { + return nil, err + } + + tokensPlugin := orchestrator.TokensPlugin{ + Plugin: plugin, + Config: config, + Name: config.GetString(coreconfig.PluginConfigName), + } + plugins[config.GetString(coreconfig.PluginConfigName)] = tokensPlugin + } + + // If there still is no tokens config, check the deprecated structure for config + if len(plugins) == 0 { + tokensConfigArraySize = deprecatedTokensConfig.ArraySize() + if tokensConfigArraySize > 0 { + log.L(ctx).Warnf("Your tokens config uses a deprecated configuration structure - the tokens configuration has been moved under the 'plugins' section") + } + + for i := 0; i < tokensConfigArraySize; i++ { + deprecatedConfig := deprecatedTokensConfig.ArrayEntry(i) + name := deprecatedConfig.GetString(coreconfig.PluginConfigName) + pluginName := deprecatedConfig.GetString(tokens.TokensConfigPlugin) + if name == "" { + return nil, i18n.NewError(ctx, coremsgs.MsgMissingTokensPluginConfig) + } + if err = core.ValidateFFNameField(ctx, name, "name"); err != nil { + return nil, err + } + + log.L(ctx).Infof("Loading tokens plugin name=%s plugin=%s", name, pluginName) + plugin, err := tifactory.GetPlugin(ctx, pluginName) + if err != nil { + return nil, err + } + + tokensPlugin := orchestrator.TokensPlugin{ + Plugin: plugin, + Config: deprecatedConfig, + Name: name, + } + plugins[name] = tokensPlugin + } + } + + return plugins, err +} + +func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map[string]orchestrator.DatabasePlugin, err error) { + plugins = make(map[string]orchestrator.DatabasePlugin) + dbConfigArraySize := databaseConfig.ArraySize() + for i := 0; i < dbConfigArraySize; i++ { + config := databaseConfig.ArrayEntry(i) + if err = nm.validatePluginConfig(ctx, config, "database"); err != nil { + return nil, err + } + + plugin, err := difactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) + if err != nil { + return nil, err + } + + dbPlugin := orchestrator.DatabasePlugin{ + Plugin: plugin, + Config: config, + } + + plugins[config.GetString(coreconfig.PluginConfigName)] = dbPlugin + } + + // check for deprecated config + if len(nm.databases) == 0 { + plugin, err := difactory.GetPlugin(ctx, deprecatedDatabaseConfig.GetString(coreconfig.PluginConfigType)) + if err != nil { + return nil, err + } + deprecatedPluginName := "database_0" + dbPlugin := orchestrator.DatabasePlugin{ + Plugin: plugin, + Config: deprecatedDatabaseConfig, + } + + plugins[deprecatedPluginName] = dbPlugin + } + + return plugins, err +} + +func (nm *namespaceManager) validatePluginConfig(ctx context.Context, config config.Section, sectionName string) error { + name := config.GetString(coreconfig.PluginConfigName) + pluginType := config.GetString(coreconfig.PluginConfigType) + + if name == "" || pluginType == "" { + return i18n.NewError(ctx, coremsgs.MsgInvalidPluginConfiguration, sectionName) + } + + if err := core.ValidateFFNameField(ctx, name, "name"); err != nil { + return err + } + + if _, ok := nm.pluginNames[name]; ok { + return i18n.NewError(ctx, coremsgs.MsgDuplicatePluginName, name) + } + nm.pluginNames[name] = true + + return nil +} + +func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins map[string]orchestrator.DataexchangePlugin, err error) { + plugins = make(map[string]orchestrator.DataexchangePlugin) + dxConfigArraySize := dataexchangeConfig.ArraySize() + for i := 0; i < dxConfigArraySize; i++ { + config := dataexchangeConfig.ArrayEntry(i) + if err = nm.validatePluginConfig(ctx, config, "dataexchange"); err != nil { + return nil, err + } + plugin, err := dxfactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) + if err != nil { + return nil, err + } + dxPlugin := orchestrator.DataexchangePlugin{ + Plugin: plugin, + Config: config, + } + + plugins[config.GetString(coreconfig.PluginConfigName)] = dxPlugin + } + + if len(plugins) == 0 { + log.L(ctx).Warnf("Your data exchange config uses a deprecated configuration structure - the data exchange configuration has been moved under the 'plugins' section") + deprecatedPluginName := "dataexchange_0" + dxType := deprecatedDataexchangeConfig.GetString(coreconfig.PluginConfigType) + plugin, err := dxfactory.GetPlugin(ctx, dxType) + if err != nil { + return nil, err + } + + dxPlugin := orchestrator.DataexchangePlugin{ + Plugin: plugin, + Config: deprecatedDataexchangeConfig, + } + + plugins[deprecatedPluginName] = dxPlugin + } + + return plugins, err +} + +func (nm *namespaceManager) getIdentityPlugins(ctx context.Context) (plugins map[string]orchestrator.IdentityPlugin, err error) { + plugins = make(map[string]orchestrator.IdentityPlugin) + configSize := identityConfig.ArraySize() + for i := 0; i < configSize; i++ { + config := identityConfig.ArrayEntry(i) + if err = nm.validatePluginConfig(ctx, config, "identity"); err != nil { + return nil, err + } + plugin, err := iifactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) + if err != nil { + return nil, err + } + + idPlugin := orchestrator.IdentityPlugin{ + Plugin: plugin, + Config: config, + } + plugins[config.GetString(coreconfig.PluginConfigName)] = idPlugin + } + + return plugins, err +} + +func (nm *namespaceManager) getBlockchainPlugins(ctx context.Context) (plugins map[string]orchestrator.BlockchainPlugin, err error) { + plugins = make(map[string]orchestrator.BlockchainPlugin) + blockchainConfigArraySize := blockchainConfig.ArraySize() + for i := 0; i < blockchainConfigArraySize; i++ { + config := blockchainConfig.ArrayEntry(i) + if err = nm.validatePluginConfig(ctx, config, "blockchain"); err != nil { + return nil, err + } + + plugin, err := bifactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) + if err != nil { + return nil, err + } + + bcPlugin := orchestrator.BlockchainPlugin{ + Plugin: plugin, + Config: config, + } + plugins[config.GetString(coreconfig.PluginConfigName)] = bcPlugin + } + + // check deprecated config + if len(plugins) == 0 { + deprecatedPluginName := "database_0" + biType := deprecatedBlockchainConfig.GetString(coreconfig.PluginConfigType) + plugin, err := bifactory.GetPlugin(ctx, biType) + if err != nil { + return nil, err + } + + bcPlugin := orchestrator.BlockchainPlugin{ + Plugin: plugin, + Config: deprecatedBlockchainConfig, + } + plugins[deprecatedPluginName] = bcPlugin + } + + return plugins, err +} + +func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugins map[string]orchestrator.SharedStoragePlugin, err error) { + plugins = make(map[string]orchestrator.SharedStoragePlugin) + configSize := sharedstorageConfig.ArraySize() + for i := 0; i < configSize; i++ { + config := sharedstorageConfig.ArrayEntry(i) + if err = nm.validatePluginConfig(ctx, config, "sharedstorage"); err != nil { + return nil, err + } + plugin, err := ssfactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) + if err != nil { + return nil, err + } + + ssPlugin := orchestrator.SharedStoragePlugin{ + Plugin: plugin, + Config: config, + } + plugins[config.GetString(coreconfig.PluginConfigName)] = ssPlugin + } + + // check deprecated config + if len(plugins) == 0 { + deprecatedPluginName := "sharedstorage_0" + ssType := deprecatedSharedStorageConfig.GetString(coreconfig.PluginConfigType) + plugin, err := ssfactory.GetPlugin(ctx, ssType) + if err != nil { + return nil, err + } + + ssPlugin := orchestrator.SharedStoragePlugin{ + Plugin: plugin, + Config: deprecatedSharedStorageConfig, + } + plugins[deprecatedPluginName] = ssPlugin + } + + return plugins, err +} + func buildNamespaceMap(ctx context.Context) map[string]config.Section { conf := namespacePredefined namespaces := make(map[string]config.Section, conf.ArraySize()) @@ -78,68 +484,24 @@ func buildNamespaceMap(ctx context.Context) map[string]config.Section { return namespaces } -func (nm *namespaceManager) Init(ctx context.Context, di database.Plugin) error { - return nm.initNamespaces(ctx, di) -} - -func (nm *namespaceManager) getPredefinedNamespaces(ctx context.Context) ([]*core.Namespace, error) { +func (nm *namespaceManager) initNamespaces(ctx context.Context, nsConfig map[string]config.Section) (err error) { defaultNS := config.GetString(coreconfig.NamespacesDefault) - namespaces := []*core.Namespace{ - { - Name: core.SystemNamespace, - Type: core.NamespaceTypeSystem, - Description: i18n.Expand(ctx, coremsgs.CoreSystemNSDescription), - }, - } i := 0 foundDefault := false - for name, nsObject := range nm.nsConfig { - if err := nm.validateNamespaceConfig(ctx, name, i, nsObject); err != nil { - return nil, err + for name, nsObject := range nsConfig { + if err := nm.buildAndValidateNamespaces(ctx, name, i, nsObject); err != nil { + return err } i++ foundDefault = foundDefault || name == defaultNS - namespaces = append(namespaces, &core.Namespace{ - Type: core.NamespaceTypeLocal, - Name: name, - Description: nsObject.GetString("description"), - }) } if !foundDefault { - return nil, i18n.NewError(ctx, coremsgs.MsgDefaultNamespaceNotFound, defaultNS) + return i18n.NewError(ctx, coremsgs.MsgDefaultNamespaceNotFound, defaultNS) } - return namespaces, nil + return err } -func (nm *namespaceManager) initNamespaces(ctx context.Context, di database.Plugin) error { - predefined, err := nm.getPredefinedNamespaces(ctx) - if err != nil { - return err - } - for _, newNS := range predefined { - ns, err := di.GetNamespace(ctx, newNS.Name) - if err != nil { - return err - } - var updated bool - if ns == nil { - updated = true - newNS.ID = fftypes.NewUUID() - newNS.Created = fftypes.Now() - } else { - // Only update if the description has changed, and the one in our DB is locally defined - updated = ns.Description != newNS.Description && ns.Type == core.NamespaceTypeLocal - } - if updated { - if err := di.UpsertNamespace(ctx, newNS, true); err != nil { - return err - } - } - } - return nil -} - -func (nm *namespaceManager) validateNamespaceConfig(ctx context.Context, name string, index int, conf config.Section) error { +func (nm *namespaceManager) buildAndValidateNamespaces(ctx context.Context, name string, index int, conf config.Section) error { if err := core.ValidateFFNameField(ctx, name, fmt.Sprintf("namespaces.predefined[%d].name", index)); err != nil { return err } @@ -153,19 +515,19 @@ func (nm *namespaceManager) validateNamespaceConfig(ctx context.Context, name st // If no plugins are found when querying the config, assume older config file if len(plugins) == 0 { - for plugin := range nm.bcPlugins { + for plugin := range nm.blockchains { plugins = append(plugins, plugin) } - for plugin := range nm.dxPlugins { + for plugin := range nm.dataexchanges { plugins = append(plugins, plugin) } - for plugin := range nm.ssPlugins { + for plugin := range nm.sharedstorages { plugins = append(plugins, plugin) } - for plugin := range nm.dbPlugins { + for plugin := range nm.databases { plugins = append(plugins, plugin) } } @@ -192,36 +554,50 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s var dxPlugin bool var bcPlugin bool + ns := namespace{ + tokens: make(map[string]orchestrator.TokensPlugin), + multiparty: true, + } + for _, pluginName := range plugins { - if _, ok := nm.bcPlugins[pluginName]; ok { + if instance, ok := nm.blockchains[pluginName]; ok { if bcPlugin { return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") } bcPlugin = true + ns.blockchain = instance continue } - if _, ok := nm.dxPlugins[pluginName]; ok { + if instance, ok := nm.dataexchanges[pluginName]; ok { if dxPlugin { return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "dataexchange") } dxPlugin = true + ns.dataexchange = instance continue } - if _, ok := nm.ssPlugins[pluginName]; ok { + if instance, ok := nm.sharedstorages[pluginName]; ok { if ssPlugin { return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "sharedstorage") } ssPlugin = true + ns.sharedstorage = instance continue } - if _, ok := nm.dbPlugins[pluginName]; ok { + if instance, ok := nm.databases[pluginName]; ok { if dbPlugin { return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") } dbPlugin = true + ns.database = instance + continue + } + if instance, ok := nm.tokens[pluginName]; ok { + ns.tokens[pluginName] = instance continue } - if _, ok := nm.tokensPlugins[pluginName]; ok { + if instance, ok := nm.identities[pluginName]; ok { + ns.identity = instance continue } @@ -231,6 +607,7 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s if !dbPlugin || !ssPlugin || !dxPlugin || !bcPlugin { return i18n.NewError(ctx, coremsgs.MsgNamespaceMultipartyConfiguration, name) } + nm.namespaces[name] = ns return nil } @@ -239,28 +616,35 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name stri var dbPlugin bool var bcPlugin bool + ns := namespace{ + tokens: make(map[string]orchestrator.TokensPlugin), + } + for _, pluginName := range plugins { - if _, ok := nm.bcPlugins[pluginName]; ok { + if instance, ok := nm.blockchains[pluginName]; ok { if bcPlugin { return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") } bcPlugin = true + ns.blockchain = instance continue } - if _, ok := nm.dxPlugins[pluginName]; ok { + if _, ok := nm.dataexchanges[pluginName]; ok { return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayInvalidPlugins, name) } - if _, ok := nm.ssPlugins[pluginName]; ok { + if _, ok := nm.sharedstorages[pluginName]; ok { return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayInvalidPlugins, name) } - if _, ok := nm.dbPlugins[pluginName]; ok { + if instance, ok := nm.databases[pluginName]; ok { if dbPlugin { return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") } dbPlugin = true + ns.database = instance continue } - if _, ok := nm.tokensPlugins[pluginName]; ok { + if instance, ok := nm.tokens[pluginName]; ok { + ns.tokens[pluginName] = instance continue } @@ -270,6 +654,7 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name stri if !dbPlugin { return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayNoDB, name) } + nm.namespaces[name] = ns return nil } diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index e13f1a69b0..2ab6c2f4d0 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -22,32 +22,23 @@ import ( "github.com/hyperledger/firefly-common/pkg/config" "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly-common/pkg/i18n" - "github.com/hyperledger/firefly-common/pkg/log" "github.com/hyperledger/firefly/internal/adminevents" "github.com/hyperledger/firefly/internal/assets" "github.com/hyperledger/firefly/internal/batch" "github.com/hyperledger/firefly/internal/batchpin" - "github.com/hyperledger/firefly/internal/blockchain/bifactory" "github.com/hyperledger/firefly/internal/broadcast" "github.com/hyperledger/firefly/internal/contracts" - "github.com/hyperledger/firefly/internal/coreconfig" "github.com/hyperledger/firefly/internal/coremsgs" "github.com/hyperledger/firefly/internal/data" - "github.com/hyperledger/firefly/internal/database/difactory" - "github.com/hyperledger/firefly/internal/dataexchange/dxfactory" "github.com/hyperledger/firefly/internal/definitions" "github.com/hyperledger/firefly/internal/events" "github.com/hyperledger/firefly/internal/identity" - "github.com/hyperledger/firefly/internal/identity/iifactory" "github.com/hyperledger/firefly/internal/metrics" - "github.com/hyperledger/firefly/internal/namespace" "github.com/hyperledger/firefly/internal/networkmap" "github.com/hyperledger/firefly/internal/operations" "github.com/hyperledger/firefly/internal/privatemessaging" "github.com/hyperledger/firefly/internal/shareddownload" - "github.com/hyperledger/firefly/internal/sharedstorage/ssfactory" "github.com/hyperledger/firefly/internal/syncasync" - "github.com/hyperledger/firefly/internal/tokens/tifactory" "github.com/hyperledger/firefly/internal/txcommon" "github.com/hyperledger/firefly/pkg/blockchain" "github.com/hyperledger/firefly/pkg/core" @@ -58,21 +49,6 @@ import ( "github.com/hyperledger/firefly/pkg/tokens" ) -var ( - blockchainConfig = config.RootArray("plugins.blockchain") - tokensConfig = config.RootArray("plugins.tokens") - databaseConfig = config.RootArray("plugins.database") - sharedstorageConfig = config.RootArray("plugins.sharedstorage") - dataexchangeConfig = config.RootArray("plugins.dataexchange") - identityConfig = config.RootArray("plugins.identity") - // Deprecated configs - deprecatedTokensConfig = config.RootArray("tokens") - deprecatedBlockchainConfig = config.RootSection("blockchain") - deprecatedDatabaseConfig = config.RootSection("database") - deprecatedSharedStorageConfig = config.RootSection("sharedstorage") - deprecatedDataexchangeConfig = config.RootSection("dataexchange") -) - // Orchestrator is the main interface behind the API, implementing the actions type Orchestrator interface { Init(ctx context.Context, cancelCtx context.CancelFunc) error @@ -145,60 +121,80 @@ type Orchestrator interface { SubmitNetworkAction(ctx context.Context, action *core.NetworkAction) error } -type orchestrator struct { - ctx context.Context - cancelCtx context.CancelFunc - started bool - database database.Plugin - databases map[string]database.Plugin - blockchain blockchain.Plugin - blockchains map[string]blockchain.Plugin - identity identity.Manager - identityPlugins map[string]idplugin.Plugin - sharedstorage sharedstorage.Plugin - sharedstoragePlugins map[string]sharedstorage.Plugin - dataexchange dataexchange.Plugin - dataexchangePlugins map[string]dataexchange.Plugin - events events.EventManager - networkmap networkmap.Manager - batch batch.Manager - broadcast broadcast.Manager - messaging privatemessaging.Manager - definitions definitions.DefinitionHandler - data data.Manager - syncasync syncasync.Bridge - batchpin batchpin.Submitter - assets assets.Manager - tokens map[string]tokens.Plugin - bc boundCallbacks - contracts contracts.Manager - node *fftypes.UUID - metrics metrics.Manager - operations operations.Manager - adminEvents adminevents.Manager - sharedDownload shareddownload.Manager - txHelper txcommon.Helper - namespace namespace.Manager - // Used to detect duplicate plugin names - pluginNames map[string]bool +// this is definitely not the right place for these structs +// maybe in the factories? +type BlockchainPlugin struct { + Plugin blockchain.Plugin + Config config.Section +} + +type DatabasePlugin struct { + Plugin database.Plugin + Config config.Section +} + +type DataexchangePlugin struct { + Plugin dataexchange.Plugin + Config config.Section } -func NewOrchestrator(withDefaults bool) Orchestrator { - or := &orchestrator{} - - // Initialize the config on all the factories - bifactory.InitConfigDeprecated(deprecatedBlockchainConfig) - bifactory.InitConfig(blockchainConfig) - difactory.InitConfigDeprecated(deprecatedDatabaseConfig) - difactory.InitConfig(databaseConfig) - ssfactory.InitConfigDeprecated(deprecatedSharedStorageConfig) - ssfactory.InitConfig(sharedstorageConfig) - dxfactory.InitConfig(dataexchangeConfig) - dxfactory.InitConfigDeprecated(deprecatedDataexchangeConfig) - iifactory.InitConfig(identityConfig) - tifactory.InitConfigDeprecated(deprecatedTokensConfig) - tifactory.InitConfig(tokensConfig) - namespace.InitConfig(withDefaults) +type SharedStoragePlugin struct { + Plugin sharedstorage.Plugin + Config config.Section +} + +type TokensPlugin struct { + Plugin tokens.Plugin + Config config.Section + Name string +} + +type IdentityPlugin struct { + Plugin idplugin.Plugin + Config config.Section +} + +type orchestrator struct { + ctx context.Context + cancelCtx context.CancelFunc + started bool + blockchain BlockchainPlugin + identity identity.Manager + idPlugin IdentityPlugin + sharedstorage SharedStoragePlugin + dataexchange DataexchangePlugin + database DatabasePlugin + events events.EventManager + networkmap networkmap.Manager + batch batch.Manager + broadcast broadcast.Manager + messaging privatemessaging.Manager + definitions definitions.DefinitionHandler + data data.Manager + syncasync syncasync.Bridge + batchpin batchpin.Submitter + assets assets.Manager + tokens map[string]TokensPlugin + bc boundCallbacks + contracts contracts.Manager + node *fftypes.UUID + metrics metrics.Manager + operations operations.Manager + adminEvents adminevents.Manager + sharedDownload shareddownload.Manager + txHelper txcommon.Helper +} + +func NewOrchestrator(bc BlockchainPlugin, db DatabasePlugin, ss SharedStoragePlugin, dx DataexchangePlugin, tokens map[string]TokensPlugin, id IdentityPlugin, metrics metrics.Manager) Orchestrator { + or := &orchestrator{ + blockchain: bc, + database: db, + sharedstorage: ss, + dataexchange: dx, + tokens: tokens, + idPlugin: id, + metrics: metrics, + } return or } @@ -207,42 +203,40 @@ func (or *orchestrator) Init(ctx context.Context, cancelCtx context.CancelFunc) or.ctx = ctx or.cancelCtx = cancelCtx err = or.initPlugins(ctx) - if err == nil { - err = or.initNamespaces(ctx) - } if err == nil { err = or.initComponents(ctx) } // Bind together the blockchain interface callbacks, with the events manager - or.bc.bi = or.blockchain + or.bc.bi = or.blockchain.Plugin or.bc.ei = or.events - or.bc.dx = or.dataexchange - or.bc.ss = or.sharedstorage + or.bc.dx = or.dataexchange.Plugin + or.bc.ss = or.sharedstorage.Plugin or.bc.om = or.operations return err } func (or *orchestrator) Start() (err error) { + // TODO: move bc start before batch if err == nil { err = or.batch.Start() } var ns *core.Namespace if err == nil { - ns, err = or.database.GetNamespace(or.ctx, core.SystemNamespace) - } - if err == nil { - for _, el := range or.blockchains { - if err = el.ConfigureContract(or.ctx, &ns.Contracts); err != nil { - break - } - if err = el.Start(); err != nil { - break - } - } - if err == nil { - err = or.database.UpsertNamespace(or.ctx, ns, true) - } - } + ns, err = or.database.Plugin.GetNamespace(or.ctx, core.SystemNamespace) + } + // if err == nil { + // for _, el := range or.blockchains { + // if err = el.ConfigureContract(or.ctx, &ns.Contracts); err != nil { + // break + // } + // if err = el.Start(); err != nil { + // break + // } + // } + // if err == nil { + // err = or.database.UpsertNamespace(or.ctx, ns, true) + // } + // } if err == nil { err = or.events.Start() } @@ -260,7 +254,7 @@ func (or *orchestrator) Start() (err error) { } if err == nil { for _, el := range or.tokens { - if err = el.Start(); err != nil { + if err = el.Plugin.Start(); err != nil { break } } @@ -347,78 +341,19 @@ func (or *orchestrator) AdminEvents() adminevents.Manager { return or.adminEvents } -func (or *orchestrator) getDatabasePlugins(ctx context.Context) (plugins []database.Plugin, err error) { - dbConfigArraySize := databaseConfig.ArraySize() - plugins = make([]database.Plugin, dbConfigArraySize) - for i := 0; i < dbConfigArraySize; i++ { - config := databaseConfig.ArrayEntry(i) - if err = or.validatePluginConfig(ctx, config, "database"); err != nil { - return nil, err - } - plugins[i], err = difactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) - if err != nil { - return nil, err - } - } - - return plugins, err -} - -func (or *orchestrator) initDatabasePlugins(ctx context.Context, plugins []database.Plugin) (err error) { - for idx, plugin := range plugins { - config := databaseConfig.ArrayEntry(idx) - err = plugin.Init(ctx, config.SubSection(config.GetString(coreconfig.PluginConfigType)), or) - if err != nil { - return err - } - name := config.GetString(coreconfig.PluginConfigName) - or.databases[name] = plugin - - if or.database == nil { - or.database = plugin - } - } - - return err -} - -func (or *orchestrator) validatePluginConfig(ctx context.Context, config config.Section, sectionName string) error { - name := config.GetString(coreconfig.PluginConfigName) - pluginType := config.GetString(coreconfig.PluginConfigType) - - if name == "" || pluginType == "" { - return i18n.NewError(ctx, coremsgs.MsgInvalidPluginConfiguration, sectionName) - } - - if err := core.ValidateFFNameField(ctx, name, "name"); err != nil { +func (or *orchestrator) initPlugins(ctx context.Context) (err error) { + err = or.database.Plugin.Init(ctx, or.database.Config, or) + if err != nil { return err } - if _, ok := or.pluginNames[name]; ok { - return i18n.NewError(ctx, coremsgs.MsgDuplicatePluginName, name) - } - or.pluginNames[name] = true - - return nil -} - -func (or *orchestrator) initDataExchange(ctx context.Context) (err error) { - or.dataexchangePlugins = make(map[string]dataexchange.Plugin) - dxConfigArraySize := dataexchangeConfig.ArraySize() - plugins := make([]dataexchange.Plugin, dxConfigArraySize) - for i := 0; i < dxConfigArraySize; i++ { - config := dataexchangeConfig.ArrayEntry(i) - if err = or.validatePluginConfig(ctx, config, "dataexchange"); err != nil { - return err - } - plugins[i], err = dxfactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) - if err != nil { - return err - } + err = or.blockchain.Plugin.Init(ctx, or.blockchain.Config, or, or.metrics) + if err != nil { + return err } fb := database.IdentityQueryFactory.NewFilter(ctx) - nodes, _, err := or.database.GetIdentities(ctx, fb.And( + nodes, _, err := or.database.Plugin.GetIdentities(ctx, fb.And( fb.Eq("type", core.IdentityTypeNode), fb.Eq("namespace", core.SystemNamespace), )) @@ -430,368 +365,34 @@ func (or *orchestrator) initDataExchange(ctx context.Context) (err error) { nodeInfo[i] = node.Profile } - if len(plugins) > 0 { - for idx, plugin := range plugins { - config := dataexchangeConfig.ArrayEntry(idx) - err = plugin.Init(ctx, config.SubSection(config.GetString(coreconfig.PluginConfigType)), nodeInfo, &or.bc) - if err != nil { - return err - } - name := config.GetString(coreconfig.PluginConfigName) - or.dataexchangePlugins[name] = plugin - if or.dataexchange == nil { - or.dataexchange = plugin - } - } - } else { - log.L(ctx).Warnf("Your data exchange config uses a deprecated configuration structure - the data exchange configuration has been moved under the 'plugins' section") - dxType := deprecatedDataexchangeConfig.GetString(coreconfig.PluginConfigType) - plugin, err := dxfactory.GetPlugin(ctx, dxType) - if err != nil { - return err - } - - config := deprecatedDataexchangeConfig.SubSection(dxType) - err = plugin.Init(ctx, config, nodeInfo, &or.bc) - if err != nil { - return err - } - or.dataexchangePlugins["dataexchange_0"] = plugin - or.dataexchange = plugin - } - - return err -} - -func (or *orchestrator) initPlugins(ctx context.Context) (err error) { - or.pluginNames = make(map[string]bool) - if or.metrics == nil { - or.metrics = metrics.NewMetricsManager(ctx) - } - - if or.databases == nil { - or.databases = make(map[string]database.Plugin) - dp, err := or.getDatabasePlugins(ctx) - if err != nil { - return err - } - err = or.initDatabasePlugins(ctx, dp) - if err != nil { - return err - } - } - - // check for deprecated db config - if len(or.databases) == 0 { - diType := deprecatedDatabaseConfig.GetString(coreconfig.PluginConfigType) - plugin, err := difactory.GetPlugin(ctx, diType) - if err != nil { - return err - } - err = or.initDeprecatedDatabasePlugin(ctx, plugin) - if err != nil { - return err - } - } - - // Not really a plugin, but this has to be initialized here after the database (at least temporarily). - // Shortly after this step, namespaces will be synced to the database and will generate notifications to adminEvents. - if or.adminEvents == nil { - or.adminEvents = adminevents.NewAdminEventManager(ctx) - } - - if or.identityPlugins == nil { - if err = or.initIdentity(ctx); err != nil { - return err - } - } - - if or.blockchains == nil { - or.blockchains = make(map[string]blockchain.Plugin) - bp, err := or.getBlockchainPlugins(ctx) - if err != nil { - return err - } - err = or.initBlockchainPlugins(ctx, bp) - if err != nil { - return err - } - } - - // Check for deprecated blockchain config - if len(or.blockchains) == 0 { - biType := deprecatedBlockchainConfig.GetString(coreconfig.PluginConfigType) - plugin, err := bifactory.GetPlugin(ctx, biType) - if err != nil { - return err - } - err = or.initDeprecatedBlockchainPlugin(ctx, plugin) - if err != nil { - return err - } - } - - if or.sharedstoragePlugins == nil { - or.sharedstoragePlugins = make(map[string]sharedstorage.Plugin) - ss, err := or.getSharedStoragePlugins(ctx) - if err != nil { - return err - } - - if err = or.initSharedStoragePlugins(ctx, ss); err != nil { - return err - } - } - - // Check for deprecated shared storage config - if len(or.sharedstoragePlugins) == 0 { - ssType := deprecatedSharedStorageConfig.GetString(coreconfig.PluginConfigType) - plugin, err := ssfactory.GetPlugin(ctx, ssType) - if err != nil { - return err - } - - if err = or.initDeprecatedSharedStoragePlugin(ctx, plugin); err != nil { - return err - } - } - - if or.dataexchangePlugins == nil { - if err = or.initDataExchange(ctx); err != nil { - return err - } - } - - if or.tokens == nil { - if err = or.initTokens(ctx); err != nil { - return err - } - } - - return nil -} - -func (or *orchestrator) initSharedStoragePlugins(ctx context.Context, plugins []sharedstorage.Plugin) (err error) { - for idx, plugin := range plugins { - config := sharedstorageConfig.ArrayEntry(idx) - err = plugin.Init(ctx, config.SubSection(config.GetString(coreconfig.PluginConfigType)), &or.bc) - if err != nil { - return err - } - name := config.GetString(coreconfig.PluginConfigName) - or.sharedstoragePlugins[name] = plugin - - if or.sharedstorage == nil { - or.sharedstorage = plugin - } - } - - return err -} - -func (or *orchestrator) initDeprecatedSharedStoragePlugin(ctx context.Context, plugin sharedstorage.Plugin) (err error) { - log.L(ctx).Warnf("Your shared storage config uses a deprecated configuration structure - the shared storage configuration has been moved under the 'plugins' section") - err = plugin.Init(ctx, deprecatedSharedStorageConfig.SubSection(plugin.Name()), &or.bc) - if err != nil { - return err - } - - or.sharedstoragePlugins["sharedstorage_0"] = plugin - or.sharedstorage = plugin - return err -} - -func (or *orchestrator) getSharedStoragePlugins(ctx context.Context) (plugins []sharedstorage.Plugin, err error) { - configSize := sharedstorageConfig.ArraySize() - plugins = make([]sharedstorage.Plugin, configSize) - for i := 0; i < configSize; i++ { - config := sharedstorageConfig.ArrayEntry(i) - if err = or.validatePluginConfig(ctx, config, "sharedstorage"); err != nil { - return nil, err - } - plugins[i], err = ssfactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) - if err != nil { - return nil, err - } - } - - return plugins, err -} - -func (or *orchestrator) initIdentity(ctx context.Context) (err error) { - or.identityPlugins = make(map[string]idplugin.Plugin) - plugins, err := or.getIdentityPlugins(ctx) - if err != nil { - return err - } - // this is a no-op currently, inits the tbd plugin - _ = or.initIdentityPlugins(ctx, plugins) - - return err -} - -func (or *orchestrator) initIdentityPlugins(ctx context.Context, plugins []idplugin.Plugin) (err error) { - for idx, plugin := range plugins { - config := identityConfig.ArrayEntry(idx) - err = plugin.Init(ctx, config.SubSection(config.GetString(coreconfig.PluginConfigType)), &or.bc) - if err != nil { - return err - } - name := config.GetString(coreconfig.PluginConfigName) - or.identityPlugins[name] = plugin - } - - return err -} - -func (or *orchestrator) getIdentityPlugins(ctx context.Context) (plugins []idplugin.Plugin, err error) { - configSize := identityConfig.ArraySize() - plugins = make([]idplugin.Plugin, configSize) - for i := 0; i < configSize; i++ { - config := identityConfig.ArrayEntry(i) - if err = or.validatePluginConfig(ctx, config, "identity"); err != nil { - return nil, err - } - - plugins[i], err = iifactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) - if err != nil { - return nil, err - } - } - return plugins, err -} - -func (or *orchestrator) getBlockchainPlugins(ctx context.Context) (plugins []blockchain.Plugin, err error) { - blockchainConfigArraySize := blockchainConfig.ArraySize() - plugins = make([]blockchain.Plugin, blockchainConfigArraySize) - for i := 0; i < blockchainConfigArraySize; i++ { - config := blockchainConfig.ArrayEntry(i) - if err = or.validatePluginConfig(ctx, config, "blockchain"); err != nil { - return nil, err - } - - plugins[i], err = bifactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) - if err != nil { - return nil, err - } - } - - return plugins, err -} - -func (or *orchestrator) initDeprecatedBlockchainPlugin(ctx context.Context, plugin blockchain.Plugin) (err error) { - log.L(ctx).Warnf("Your blockchain config uses a deprecated configuration structure - the blockchain configuration has been moved under the 'plugins' section") - err = plugin.Init(ctx, deprecatedBlockchainConfig.SubSection(plugin.Name()), &or.bc, or.metrics) + err = or.dataexchange.Plugin.Init(ctx, or.dataexchange.Config, nodeInfo, &or.bc) if err != nil { return err } - deprecatedPluginName := "blockchain_0" - or.blockchains[deprecatedPluginName] = plugin - or.blockchain = plugin - return err -} - -func (or *orchestrator) initDeprecatedDatabasePlugin(ctx context.Context, plugin database.Plugin) (err error) { - log.L(ctx).Warnf("Your database config uses a deprecated configuration structure - the database configuration has been moved under the 'plugins' section") - err = plugin.Init(ctx, deprecatedDatabaseConfig.SubSection(plugin.Name()), or) + err = or.sharedstorage.Plugin.Init(ctx, or.sharedstorage.Config, &or.bc) if err != nil { return err } - deprecatedPluginName := "database_0" - or.databases[deprecatedPluginName] = plugin - or.database = plugin - return err -} - -func (or *orchestrator) initBlockchainPlugins(ctx context.Context, plugins []blockchain.Plugin) (err error) { - for idx, plugin := range plugins { - config := blockchainConfig.ArrayEntry(idx) - err = plugin.Init(ctx, config, &or.bc, or.metrics) - if err != nil { - return err - } - name := config.GetString(coreconfig.PluginConfigName) - or.blockchains[name] = plugin - - if or.blockchain == nil { - or.blockchain = plugin - } + for _, token := range or.tokens { + err = token.Plugin.Init(ctx, token.Name, token.Config, &or.bc) } return err } -func (or *orchestrator) initTokens(ctx context.Context) (err error) { - or.tokens = make(map[string]tokens.Plugin) - tokensConfigArraySize := tokensConfig.ArraySize() - for i := 0; i < tokensConfigArraySize; i++ { - config := tokensConfig.ArrayEntry(i) - name := config.GetString(coreconfig.PluginConfigName) - pluginType := config.GetString(coreconfig.PluginConfigType) - if err = or.validatePluginConfig(ctx, config, "tokens"); err != nil { - return err - } - - log.L(ctx).Infof("Loading tokens plugin name=%s type=%s", name, pluginType) - pluginConfig := config.SubSection(pluginType) - - plugin, err := tifactory.GetPlugin(ctx, pluginType) - if plugin != nil { - err = plugin.Init(ctx, name, pluginConfig, &or.bc) - } - if err != nil { - return err - } - or.tokens[name] = plugin - } - - if len(or.tokens) > 0 { - return nil - } - - // If there still is no tokens config, check the deprecated structure for config - tokensConfigArraySize = deprecatedTokensConfig.ArraySize() - if tokensConfigArraySize > 0 { - log.L(ctx).Warnf("Your tokens config uses a deprecated configuration structure - the tokens configuration has been moved under the 'plugins' section") - } - - for i := 0; i < tokensConfigArraySize; i++ { - prefix := deprecatedTokensConfig.ArrayEntry(i) - name := prefix.GetString(coreconfig.PluginConfigName) - pluginName := prefix.GetString(tokens.TokensConfigPlugin) - if name == "" { - return i18n.NewError(ctx, coremsgs.MsgMissingTokensPluginConfig) - } - if err = core.ValidateFFNameField(ctx, name, "name"); err != nil { - return err - } - - log.L(ctx).Infof("Loading tokens plugin name=%s plugin=%s", name, pluginName) - plugin, err := tifactory.GetPlugin(ctx, pluginName) - if plugin != nil { - err = plugin.Init(ctx, name, prefix, &or.bc) - } - if err != nil { - return err - } - or.tokens[name] = plugin - } - return nil -} - func (or *orchestrator) initComponents(ctx context.Context) (err error) { if or.data == nil { - or.data, err = data.NewDataManager(ctx, or.database, or.sharedstorage, or.dataexchange) + or.data, err = data.NewDataManager(ctx, or.database.Plugin, or.sharedstorage.Plugin, or.dataexchange.Plugin) if err != nil { return err } } if or.txHelper == nil { - or.txHelper = txcommon.NewTransactionHelper(or.database, or.data) + or.txHelper = txcommon.NewTransactionHelper(or.database.Plugin, or.data) } if or.identity == nil { @@ -802,75 +403,75 @@ func (or *orchestrator) initComponents(ctx context.Context) (err error) { } if or.batch == nil { - or.batch, err = batch.NewBatchManager(ctx, or, or.database, or.data, or.txHelper) + or.batch, err = batch.NewBatchManager(ctx, or, or.database.Plugin, or.data, or.txHelper) if err != nil { return err } } if or.operations == nil { - if or.operations, err = operations.NewOperationsManager(ctx, or.database, or.txHelper); err != nil { + if or.operations, err = operations.NewOperationsManager(ctx, or.database.Plugin, or.txHelper); err != nil { return err } } - or.syncasync = syncasync.NewSyncAsyncBridge(ctx, or.database, or.data) + or.syncasync = syncasync.NewSyncAsyncBridge(ctx, or.database.Plugin, or.data) if or.batchpin == nil { - if or.batchpin, err = batchpin.NewBatchPinSubmitter(ctx, or.database, or.identity, or.blockchain, or.metrics, or.operations); err != nil { + if or.batchpin, err = batchpin.NewBatchPinSubmitter(ctx, or.database.Plugin, or.identity, or.blockchain.Plugin, or.metrics, or.operations); err != nil { return err } } if or.messaging == nil { - if or.messaging, err = privatemessaging.NewPrivateMessaging(ctx, or.database, or.identity, or.dataexchange, or.blockchain, or.batch, or.data, or.syncasync, or.batchpin, or.metrics, or.operations); err != nil { + if or.messaging, err = privatemessaging.NewPrivateMessaging(ctx, or.database.Plugin, or.identity, or.dataexchange.Plugin, or.blockchain.Plugin, or.batch, or.data, or.syncasync, or.batchpin, or.metrics, or.operations); err != nil { return err } } if or.broadcast == nil { - if or.broadcast, err = broadcast.NewBroadcastManager(ctx, or.database, or.identity, or.data, or.blockchain, or.dataexchange, or.sharedstorage, or.batch, or.syncasync, or.batchpin, or.metrics, or.operations); err != nil { + if or.broadcast, err = broadcast.NewBroadcastManager(ctx, or.database.Plugin, or.identity, or.data, or.blockchain.Plugin, or.dataexchange.Plugin, or.sharedstorage.Plugin, or.batch, or.syncasync, or.batchpin, or.metrics, or.operations); err != nil { return err } } if or.assets == nil { - or.assets, err = assets.NewAssetManager(ctx, or.database, or.identity, or.data, or.syncasync, or.broadcast, or.messaging, or.tokens, or.metrics, or.operations, or.txHelper) + or.assets, err = assets.NewAssetManager(ctx, or.database.Plugin, or.identity, or.data, or.syncasync, or.broadcast, or.messaging, or.tokens, or.metrics, or.operations, or.txHelper) if err != nil { return err } } if or.contracts == nil { - or.contracts, err = contracts.NewContractManager(ctx, or.database, or.broadcast, or.identity, or.blockchain, or.operations, or.txHelper, or.syncasync) + or.contracts, err = contracts.NewContractManager(ctx, or.database.Plugin, or.broadcast, or.identity, or.blockchain.Plugin, or.operations, or.txHelper, or.syncasync) if err != nil { return err } } if or.definitions == nil { - or.definitions, err = definitions.NewDefinitionHandler(ctx, or.database, or.blockchain, or.dataexchange, or.data, or.identity, or.assets, or.contracts) + or.definitions, err = definitions.NewDefinitionHandler(ctx, or.database.Plugin, or.blockchain.Plugin, or.dataexchange.Plugin, or.data, or.identity, or.assets, or.contracts) if err != nil { return err } } if or.sharedDownload == nil { - or.sharedDownload, err = shareddownload.NewDownloadManager(ctx, or.database, or.sharedstorage, or.dataexchange, or.operations, &or.bc) + or.sharedDownload, err = shareddownload.NewDownloadManager(ctx, or.database.Plugin, or.sharedstorage.Plugin, or.dataexchange.Plugin, or.operations, &or.bc) if err != nil { return err } } if or.events == nil { - or.events, err = events.NewEventManager(ctx, or, or.sharedstorage, or.database, or.blockchain, or.identity, or.definitions, or.data, or.broadcast, or.messaging, or.assets, or.sharedDownload, or.metrics, or.txHelper) + or.events, err = events.NewEventManager(ctx, or, or.sharedstorage.Plugin, or.database.Plugin, or.blockchain.Plugin, or.identity, or.definitions, or.data, or.broadcast, or.messaging, or.assets, or.sharedDownload, or.metrics, or.txHelper) if err != nil { return err } } if or.networkmap == nil { - or.networkmap, err = networkmap.NewNetworkMap(ctx, or.database, or.broadcast, or.dataexchange, or.identity, or.syncasync) + or.networkmap, err = networkmap.NewNetworkMap(ctx, or.database.Plugin, or.broadcast, or.dataexchange.Plugin, or.identity, or.syncasync) if err != nil { return err } @@ -881,13 +482,6 @@ func (or *orchestrator) initComponents(ctx context.Context) (err error) { return nil } -func (or *orchestrator) initNamespaces(ctx context.Context) (err error) { - if or.namespace == nil { - or.namespace = namespace.NewNamespaceManager(ctx, or.blockchains, or.databases, or.dataexchangePlugins, or.sharedstoragePlugins, or.tokens) - } - return or.namespace.Init(ctx, or.database) -} - func (or *orchestrator) SubmitNetworkAction(ctx context.Context, action *core.NetworkAction) error { verifier, err := or.identity.GetNodeOwnerBlockchainKey(ctx) if err != nil { @@ -896,5 +490,5 @@ func (or *orchestrator) SubmitNetworkAction(ctx context.Context, action *core.Ne if action.Type != core.NetworkActionTerminate { return i18n.NewError(ctx, coremsgs.MsgUnrecognizedNetworkAction, action.Type) } - return or.blockchain.SubmitNetworkAction(ctx, fftypes.NewUUID(), verifier.Value, action.Type) + return or.blockchain.Plugin.SubmitNetworkAction(ctx, fftypes.NewUUID(), verifier.Value, action.Type) } From 056e8b1525b76aba1fe5f2dbae9b8e9b6f1119f4 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 3 Jun 2022 11:59:50 -0400 Subject: [PATCH 02/33] Instantiate Namespace Manager as the root object Signed-off-by: Andrew Richardson --- cmd/firefly.go | 34 ++++---- cmd/firefly_test.go | 44 +++++----- .../route_delete_contract_listener.go | 3 +- .../apiserver/route_delete_subscription.go | 3 +- internal/apiserver/route_get_batch_by_id.go | 3 +- internal/apiserver/route_get_batches.go | 3 +- .../route_get_blockchain_event_by_id.go | 3 +- .../apiserver/route_get_blockchain_events.go | 3 +- .../apiserver/route_get_chart_histogram.go | 3 +- .../route_get_contract_api_by_name.go | 3 +- .../route_get_contract_api_interface.go | 3 +- .../route_get_contract_api_listeners.go | 3 +- internal/apiserver/route_get_contract_apis.go | 3 +- .../apiserver/route_get_contract_interface.go | 5 +- ...ute_get_contract_interface_name_version.go | 5 +- .../route_get_contract_interfaces.go | 3 +- ...ute_get_contract_listener_by_name_or_id.go | 3 +- .../apiserver/route_get_contract_listeners.go | 3 +- internal/apiserver/route_get_data.go | 3 +- internal/apiserver/route_get_data_blob.go | 3 +- internal/apiserver/route_get_data_by_id.go | 3 +- internal/apiserver/route_get_data_msgs.go | 3 +- .../apiserver/route_get_datatype_by_name.go | 3 +- internal/apiserver/route_get_datatypes.go | 3 +- internal/apiserver/route_get_event_by_id.go | 3 +- internal/apiserver/route_get_events.go | 5 +- internal/apiserver/route_get_group_by_id.go | 3 +- internal/apiserver/route_get_groups.go | 3 +- internal/apiserver/route_get_identities.go | 5 +- .../apiserver/route_get_identity_by_id.go | 5 +- internal/apiserver/route_get_identity_did.go | 3 +- .../apiserver/route_get_identity_verifiers.go | 3 +- internal/apiserver/route_get_msg_by_id.go | 5 +- internal/apiserver/route_get_msg_data.go | 3 +- internal/apiserver/route_get_msg_events.go | 3 +- internal/apiserver/route_get_msg_txn.go | 3 +- internal/apiserver/route_get_msgs.go | 5 +- internal/apiserver/route_get_namespace.go | 3 +- internal/apiserver/route_get_namespaces.go | 2 +- internal/apiserver/route_get_net_did.go | 5 +- internal/apiserver/route_get_net_diddoc.go | 3 +- .../apiserver/route_get_net_identities.go | 5 +- internal/apiserver/route_get_net_node.go | 3 +- internal/apiserver/route_get_net_nodes.go | 3 +- internal/apiserver/route_get_net_org.go | 3 +- internal/apiserver/route_get_net_orgs.go | 3 +- internal/apiserver/route_get_op_by_id.go | 3 +- internal/apiserver/route_get_ops.go | 3 +- internal/apiserver/route_get_status.go | 3 +- .../apiserver/route_get_subscription_by_id.go | 3 +- internal/apiserver/route_get_subscriptions.go | 3 +- .../route_get_token_account_pools.go | 3 +- .../apiserver/route_get_token_accounts.go | 3 +- .../apiserver/route_get_token_approvals.go | 3 +- .../apiserver/route_get_token_balances.go | 3 +- .../apiserver/route_get_token_connectors.go | 3 +- .../route_get_token_pool_by_name_or_id.go | 3 +- internal/apiserver/route_get_token_pools.go | 3 +- .../route_get_token_transfer_by_id.go | 3 +- .../apiserver/route_get_token_transfers.go | 3 +- .../route_get_txn_blockchainevents.go | 3 +- internal/apiserver/route_get_txn_by_id.go | 3 +- internal/apiserver/route_get_txn_ops.go | 3 +- internal/apiserver/route_get_txn_status.go | 3 +- internal/apiserver/route_get_txns.go | 3 +- .../apiserver/route_get_verifier_by_id.go | 3 +- internal/apiserver/route_get_verifiers.go | 3 +- .../apiserver/route_patch_update_identity.go | 3 +- .../route_post_contract_api_invoke.go | 3 +- .../route_post_contract_api_listeners.go | 3 +- .../route_post_contract_api_query.go | 3 +- .../route_post_contract_interface_generate.go | 3 +- .../apiserver/route_post_contract_invoke.go | 3 +- .../apiserver/route_post_contract_query.go | 3 +- internal/apiserver/route_post_data.go | 6 +- .../apiserver/route_post_network_action.go | 3 +- .../apiserver/route_post_new_contract_api.go | 3 +- .../route_post_new_contract_interface.go | 3 +- .../route_post_new_contract_listener.go | 3 +- internal/apiserver/route_post_new_datatype.go | 3 +- internal/apiserver/route_post_new_identity.go | 3 +- .../route_post_new_message_broadcast.go | 3 +- .../route_post_new_message_private.go | 3 +- .../route_post_new_message_requestreply.go | 3 +- .../apiserver/route_post_new_namespace.go | 46 ----------- .../route_post_new_namespace_test.go | 65 --------------- .../apiserver/route_post_new_node_self.go | 3 +- .../apiserver/route_post_new_organization.go | 3 +- .../route_post_new_organization_self.go | 3 +- .../apiserver/route_post_new_subscription.go | 3 +- internal/apiserver/route_post_op_retry.go | 3 +- .../apiserver/route_post_token_approval.go | 3 +- internal/apiserver/route_post_token_burn.go | 3 +- internal/apiserver/route_post_token_mint.go | 3 +- internal/apiserver/route_post_token_pool.go | 3 +- .../apiserver/route_post_token_transfer.go | 3 +- internal/apiserver/route_put_contract_api.go | 3 +- internal/apiserver/route_put_subscription.go | 3 +- internal/apiserver/routes.go | 1 - internal/apiserver/server.go | 45 ++++++----- internal/identity/identitymanager.go | 4 +- internal/namespace/manager.go | 52 +++++++----- internal/oapispec/apirequest.go | 4 +- internal/orchestrator/chart.go | 2 +- internal/orchestrator/data_query.go | 62 +++++++------- internal/orchestrator/orchestrator.go | 41 +++++----- internal/orchestrator/status.go | 47 ++++------- internal/orchestrator/subscriptions.go | 6 +- internal/orchestrator/txn_status.go | 8 +- mocks/apiservermocks/server.go | 12 +-- mocks/namespacemocks/manager.go | 81 +++++++++++++++++-- 111 files changed, 454 insertions(+), 402 deletions(-) delete mode 100644 internal/apiserver/route_post_new_namespace.go delete mode 100644 internal/apiserver/route_post_new_namespace_test.go diff --git a/cmd/firefly.go b/cmd/firefly.go index 6d4a7bd601..4a9d37c887 100644 --- a/cmd/firefly.go +++ b/cmd/firefly.go @@ -31,7 +31,7 @@ import ( "github.com/hyperledger/firefly-common/pkg/log" "github.com/hyperledger/firefly/internal/apiserver" "github.com/hyperledger/firefly/internal/coreconfig" - "github.com/hyperledger/firefly/internal/orchestrator" + "github.com/hyperledger/firefly/internal/namespace" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -58,7 +58,7 @@ var showConfigCommand = &cobra.Command{ Short: "List out the configuration options", Run: func(cmd *cobra.Command, args []string) { // Initialize config of all plugins - getOrchestrator() + getRootManager() _ = config.ReadConfig(configSuffix, cfgFile) // Print it all out @@ -72,18 +72,18 @@ var showConfigCommand = &cobra.Command{ var cfgFile string -var _utOrchestrator orchestrator.Orchestrator +var _utManager namespace.Manager func init() { rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "f", "", "config file") rootCmd.AddCommand(showConfigCommand) } -func getOrchestrator() orchestrator.Orchestrator { - if _utOrchestrator != nil { - return _utOrchestrator +func getRootManager() namespace.Manager { + if _utManager != nil { + return _utManager } - return orchestrator.NewOrchestrator(true) + return namespace.NewNamespaceManager(true) } // Execute is called by the main method of the package @@ -118,19 +118,19 @@ func run() error { signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) for { - orchestratorCtx, cancelOrchestratorCtx := context.WithCancel(ctx) - o := getOrchestrator() + rootCtx, rootCancelCtx := context.WithCancel(ctx) + mgr := getRootManager() as := apiserver.NewAPIServer() - go startFirefly(orchestratorCtx, cancelOrchestratorCtx, o, as, errChan) + go startFirefly(rootCtx, rootCancelCtx, mgr, as, errChan) select { case sig := <-sigs: log.L(ctx).Infof("Shutting down due to %s", sig.String()) cancelCtx() - o.WaitStop() + mgr.WaitStop() return nil - case <-orchestratorCtx.Done(): + case <-rootCtx.Done(): log.L(ctx).Infof("Restarting due to configuration change") - o.WaitStop() + mgr.WaitStop() // Re-read the configuration coreconfig.Reset() if err := config.ReadConfig(configSuffix, cfgFile); err != nil { @@ -144,7 +144,7 @@ func run() error { } } -func startFirefly(ctx context.Context, cancelCtx context.CancelFunc, o orchestrator.Orchestrator, as apiserver.Server, errChan chan error) { +func startFirefly(ctx context.Context, cancelCtx context.CancelFunc, mgr namespace.Manager, as apiserver.Server, errChan chan error) { var err error // Start debug listener debugPort := config.GetInt(coreconfig.DebugPort) @@ -161,18 +161,18 @@ func startFirefly(ctx context.Context, cancelCtx context.CancelFunc, o orchestra log.L(ctx).Debugf("Debug HTTP endpoint listening on localhost:%d", debugPort) } - if err = o.Init(ctx, cancelCtx); err != nil { + if err = mgr.Init(ctx, cancelCtx); err != nil { errChan <- err return } - if err = o.Start(); err != nil { + if err = mgr.Start(); err != nil { errChan <- err return } // Run the API Server - if err = as.Serve(ctx, o); err != nil { + if err = as.Serve(ctx, mgr); err != nil { errChan <- err } } diff --git a/cmd/firefly_test.go b/cmd/firefly_test.go index b464ce77f0..167fa389fe 100644 --- a/cmd/firefly_test.go +++ b/cmd/firefly_test.go @@ -24,7 +24,7 @@ import ( "testing" "github.com/hyperledger/firefly/mocks/apiservermocks" - "github.com/hyperledger/firefly/mocks/orchestratormocks" + "github.com/hyperledger/firefly/mocks/namespacemocks" "github.com/spf13/viper" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -33,20 +33,20 @@ import ( const configDir = "../test/data/config" func TestGetEngine(t *testing.T) { - assert.NotNil(t, getOrchestrator()) + assert.NotNil(t, getRootManager()) } func TestExecMissingConfig(t *testing.T) { - _utOrchestrator = &orchestratormocks.Orchestrator{} - defer func() { _utOrchestrator = nil }() + _utManager = &namespacemocks.Manager{} + defer func() { _utManager = nil }() viper.Reset() err := Execute() assert.Regexp(t, "Not Found", err) } func TestShowConfig(t *testing.T) { - _utOrchestrator = &orchestratormocks.Orchestrator{} - defer func() { _utOrchestrator = nil }() + _utManager = &namespacemocks.Manager{} + defer func() { _utManager = nil }() viper.Reset() rootCmd.SetArgs([]string{"showconf"}) defer rootCmd.SetArgs([]string{}) @@ -55,33 +55,33 @@ func TestShowConfig(t *testing.T) { } func TestExecEngineInitFail(t *testing.T) { - o := &orchestratormocks.Orchestrator{} + o := &namespacemocks.Manager{} o.On("Init", mock.Anything, mock.Anything).Return(fmt.Errorf("splutter")) - _utOrchestrator = o - defer func() { _utOrchestrator = nil }() + _utManager = o + defer func() { _utManager = nil }() os.Chdir(configDir) err := Execute() assert.Regexp(t, "splutter", err) } func TestExecEngineStartFail(t *testing.T) { - o := &orchestratormocks.Orchestrator{} + o := &namespacemocks.Manager{} o.On("Init", mock.Anything, mock.Anything).Return(nil) o.On("Start").Return(fmt.Errorf("bang")) - _utOrchestrator = o - defer func() { _utOrchestrator = nil }() + _utManager = o + defer func() { _utManager = nil }() os.Chdir(configDir) err := Execute() assert.Regexp(t, "bang", err) } func TestExecOkExitSIGINT(t *testing.T) { - o := &orchestratormocks.Orchestrator{} + o := &namespacemocks.Manager{} o.On("Init", mock.Anything, mock.Anything).Return(nil) o.On("Start").Return(nil) o.On("WaitStop").Return() - _utOrchestrator = o - defer func() { _utOrchestrator = nil }() + _utManager = o + defer func() { _utManager = nil }() os.Chdir(configDir) go func() { @@ -92,7 +92,7 @@ func TestExecOkExitSIGINT(t *testing.T) { } func TestExecOkRestartThenExit(t *testing.T) { - o := &orchestratormocks.Orchestrator{} + o := &namespacemocks.Manager{} var orContext context.Context initCount := 0 init := o.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) @@ -110,8 +110,8 @@ func TestExecOkRestartThenExit(t *testing.T) { ws.RunFn = func(a mock.Arguments) { <-orContext.Done() } - _utOrchestrator = o - defer func() { _utOrchestrator = nil }() + _utManager = o + defer func() { _utManager = nil }() os.Chdir(configDir) err := Execute() @@ -119,7 +119,7 @@ func TestExecOkRestartThenExit(t *testing.T) { } func TestExecOkRestartConfigProblem(t *testing.T) { - o := &orchestratormocks.Orchestrator{} + o := &namespacemocks.Manager{} tmpDir, err := os.MkdirTemp(os.TempDir(), "ut") assert.NoError(t, err) defer os.RemoveAll(tmpDir) @@ -135,8 +135,8 @@ func TestExecOkRestartConfigProblem(t *testing.T) { <-orContext.Done() os.Chdir(tmpDir) // this will mean we fail to read the config }) - _utOrchestrator = o - defer func() { _utOrchestrator = nil }() + _utManager = o + defer func() { _utManager = nil }() os.Chdir(configDir) err = Execute() @@ -144,7 +144,7 @@ func TestExecOkRestartConfigProblem(t *testing.T) { } func TestAPIServerError(t *testing.T) { - o := &orchestratormocks.Orchestrator{} + o := &namespacemocks.Manager{} o.On("Init", mock.Anything, mock.Anything).Return(nil) o.On("Start").Return(nil) as := &apiservermocks.Server{} diff --git a/internal/apiserver/route_delete_contract_listener.go b/internal/apiserver/route_delete_contract_listener.go index 56c3cfbae0..266e290029 100644 --- a/internal/apiserver/route_delete_contract_listener.go +++ b/internal/apiserver/route_delete_contract_listener.go @@ -37,7 +37,8 @@ var deleteContractListener = &oapispec.Route{ JSONOutputValue: nil, JSONOutputCodes: []int{http.StatusNoContent}, // Sync operation, no output JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - err = getOr(r.Ctx).Contracts().DeleteContractListenerByNameOrID(r.Ctx, extractNamespace(r.PP), r.PP["nameOrId"]) + ns := extractNamespace(r.PP) + err = getOr(r.Ctx, ns).Contracts().DeleteContractListenerByNameOrID(r.Ctx, ns, r.PP["nameOrId"]) return nil, err }, } diff --git a/internal/apiserver/route_delete_subscription.go b/internal/apiserver/route_delete_subscription.go index 1dd8d64b7d..61e4a7719e 100644 --- a/internal/apiserver/route_delete_subscription.go +++ b/internal/apiserver/route_delete_subscription.go @@ -37,7 +37,8 @@ var deleteSubscription = &oapispec.Route{ JSONOutputValue: nil, JSONOutputCodes: []int{http.StatusNoContent}, // Sync operation, no output JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - err = getOr(r.Ctx).DeleteSubscription(r.Ctx, extractNamespace(r.PP), r.PP["subid"]) + ns := extractNamespace(r.PP) + err = getOr(r.Ctx, ns).DeleteSubscription(r.Ctx, ns, r.PP["subid"]) return nil, err }, } diff --git a/internal/apiserver/route_get_batch_by_id.go b/internal/apiserver/route_get_batch_by_id.go index ee5a3a169b..a5cb02a71e 100644 --- a/internal/apiserver/route_get_batch_by_id.go +++ b/internal/apiserver/route_get_batch_by_id.go @@ -38,7 +38,8 @@ var getBatchByID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.BatchPersisted{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).GetBatchByID(r.Ctx, extractNamespace(r.PP), r.PP["batchid"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).GetBatchByID(r.Ctx, ns, r.PP["batchid"]) return output, err }, } diff --git a/internal/apiserver/route_get_batches.go b/internal/apiserver/route_get_batches.go index f45635b2bc..1ec29f92f3 100644 --- a/internal/apiserver/route_get_batches.go +++ b/internal/apiserver/route_get_batches.go @@ -37,6 +37,7 @@ var getBatches = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.BatchPersisted{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetBatches(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).GetBatches(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_blockchain_event_by_id.go b/internal/apiserver/route_get_blockchain_event_by_id.go index 7f5cd180aa..242122c69f 100644 --- a/internal/apiserver/route_get_blockchain_event_by_id.go +++ b/internal/apiserver/route_get_blockchain_event_by_id.go @@ -38,6 +38,7 @@ var getBlockchainEventByID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.BlockchainEvent{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return getOr(r.Ctx).GetBlockchainEventByID(r.Ctx, extractNamespace(r.PP), r.PP["id"]) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).GetBlockchainEventByID(r.Ctx, ns, r.PP["id"]) }, } diff --git a/internal/apiserver/route_get_blockchain_events.go b/internal/apiserver/route_get_blockchain_events.go index 2515786b79..1b8eda97fb 100644 --- a/internal/apiserver/route_get_blockchain_events.go +++ b/internal/apiserver/route_get_blockchain_events.go @@ -37,6 +37,7 @@ var getBlockchainEvents = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.BlockchainEvent{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetBlockchainEvents(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).GetBlockchainEvents(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_chart_histogram.go b/internal/apiserver/route_get_chart_histogram.go index 3c561cff07..c8a1fd73c5 100644 --- a/internal/apiserver/route_get_chart_histogram.go +++ b/internal/apiserver/route_get_chart_histogram.go @@ -58,6 +58,7 @@ var getChartHistogram = &oapispec.Route{ if err != nil { return nil, i18n.NewError(r.Ctx, coremsgs.MsgInvalidChartNumberParam, "buckets") } - return getOr(r.Ctx).GetChartHistogram(r.Ctx, extractNamespace(r.PP), startTime.UnixNano(), endTime.UnixNano(), buckets, database.CollectionName(r.PP["collection"])) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).GetChartHistogram(r.Ctx, ns, startTime.UnixNano(), endTime.UnixNano(), buckets, database.CollectionName(r.PP["collection"])) }, } diff --git a/internal/apiserver/route_get_contract_api_by_name.go b/internal/apiserver/route_get_contract_api_by_name.go index 3725c7d82e..ccbd4c853a 100644 --- a/internal/apiserver/route_get_contract_api_by_name.go +++ b/internal/apiserver/route_get_contract_api_by_name.go @@ -38,6 +38,7 @@ var getContractAPIByName = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.ContractAPI{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return getOr(r.Ctx).Contracts().GetContractAPI(r.Ctx, r.APIBaseURL, extractNamespace(r.PP), r.PP["apiName"]) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Contracts().GetContractAPI(r.Ctx, r.APIBaseURL, extractNamespace(r.PP), r.PP["apiName"]) }, } diff --git a/internal/apiserver/route_get_contract_api_interface.go b/internal/apiserver/route_get_contract_api_interface.go index 97004eee14..94664f552a 100644 --- a/internal/apiserver/route_get_contract_api_interface.go +++ b/internal/apiserver/route_get_contract_api_interface.go @@ -38,6 +38,7 @@ var getContractAPIInterface = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.FFI{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return getOr(r.Ctx).Contracts().GetContractAPIInterface(r.Ctx, extractNamespace(r.PP), r.PP["apiName"]) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Contracts().GetContractAPIInterface(r.Ctx, ns, r.PP["apiName"]) }, } diff --git a/internal/apiserver/route_get_contract_api_listeners.go b/internal/apiserver/route_get_contract_api_listeners.go index 7da4f208a4..59efebc85d 100644 --- a/internal/apiserver/route_get_contract_api_listeners.go +++ b/internal/apiserver/route_get_contract_api_listeners.go @@ -40,6 +40,7 @@ var getContractAPIListeners = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.ContractListener{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).Contracts().GetContractAPIListeners(r.Ctx, extractNamespace(r.PP), r.PP["apiName"], r.PP["eventPath"], r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).Contracts().GetContractAPIListeners(r.Ctx, ns, r.PP["apiName"], r.PP["eventPath"], r.Filter)) }, } diff --git a/internal/apiserver/route_get_contract_apis.go b/internal/apiserver/route_get_contract_apis.go index 648126b152..fdd5a44959 100644 --- a/internal/apiserver/route_get_contract_apis.go +++ b/internal/apiserver/route_get_contract_apis.go @@ -37,6 +37,7 @@ var getContractAPIs = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.ContractAPI{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).Contracts().GetContractAPIs(r.Ctx, r.APIBaseURL, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).Contracts().GetContractAPIs(r.Ctx, r.APIBaseURL, extractNamespace(r.PP), r.Filter)) }, } diff --git a/internal/apiserver/route_get_contract_interface.go b/internal/apiserver/route_get_contract_interface.go index e216a8e556..154ee2acd7 100644 --- a/internal/apiserver/route_get_contract_interface.go +++ b/internal/apiserver/route_get_contract_interface.go @@ -46,9 +46,10 @@ var getContractInterface = &oapispec.Route{ if err != nil { return nil, err } + ns := extractNamespace(r.PP) if strings.EqualFold(r.QP["fetchchildren"], "true") { - return getOr(r.Ctx).Contracts().GetFFIByIDWithChildren(r.Ctx, interfaceID) + return getOr(r.Ctx, ns).Contracts().GetFFIByIDWithChildren(r.Ctx, interfaceID) } - return getOr(r.Ctx).Contracts().GetFFIByID(r.Ctx, interfaceID) + return getOr(r.Ctx, ns).Contracts().GetFFIByID(r.Ctx, interfaceID) }, } diff --git a/internal/apiserver/route_get_contract_interface_name_version.go b/internal/apiserver/route_get_contract_interface_name_version.go index 8881bdcb30..acd15d0f30 100644 --- a/internal/apiserver/route_get_contract_interface_name_version.go +++ b/internal/apiserver/route_get_contract_interface_name_version.go @@ -42,9 +42,10 @@ var getContractInterfaceNameVersion = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.FFI{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + ns := extractNamespace(r.PP) if strings.EqualFold(r.QP["fetchchildren"], "true") { - return getOr(r.Ctx).Contracts().GetFFIWithChildren(r.Ctx, extractNamespace(r.PP), r.PP["name"], r.PP["version"]) + return getOr(r.Ctx, ns).Contracts().GetFFIWithChildren(r.Ctx, ns, r.PP["name"], r.PP["version"]) } - return getOr(r.Ctx).Contracts().GetFFI(r.Ctx, extractNamespace(r.PP), r.PP["name"], r.PP["version"]) + return getOr(r.Ctx, ns).Contracts().GetFFI(r.Ctx, ns, r.PP["name"], r.PP["version"]) }, } diff --git a/internal/apiserver/route_get_contract_interfaces.go b/internal/apiserver/route_get_contract_interfaces.go index b6955407c1..ca4e6d361d 100644 --- a/internal/apiserver/route_get_contract_interfaces.go +++ b/internal/apiserver/route_get_contract_interfaces.go @@ -37,6 +37,7 @@ var getContractInterfaces = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.FFI{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).Contracts().GetFFIs(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).Contracts().GetFFIs(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_contract_listener_by_name_or_id.go b/internal/apiserver/route_get_contract_listener_by_name_or_id.go index 0e3d7b699c..82e9649134 100644 --- a/internal/apiserver/route_get_contract_listener_by_name_or_id.go +++ b/internal/apiserver/route_get_contract_listener_by_name_or_id.go @@ -38,6 +38,7 @@ var getContractListenerByNameOrID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.ContractListener{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return getOr(r.Ctx).Contracts().GetContractListenerByNameOrID(r.Ctx, extractNamespace(r.PP), r.PP["nameOrId"]) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Contracts().GetContractListenerByNameOrID(r.Ctx, ns, r.PP["nameOrId"]) }, } diff --git a/internal/apiserver/route_get_contract_listeners.go b/internal/apiserver/route_get_contract_listeners.go index 25c0f135f5..df95a98b10 100644 --- a/internal/apiserver/route_get_contract_listeners.go +++ b/internal/apiserver/route_get_contract_listeners.go @@ -37,6 +37,7 @@ var getContractListeners = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.ContractListener{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).Contracts().GetContractListeners(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).Contracts().GetContractListeners(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_data.go b/internal/apiserver/route_get_data.go index 41d663f7fe..b7c19b0ba5 100644 --- a/internal/apiserver/route_get_data.go +++ b/internal/apiserver/route_get_data.go @@ -37,6 +37,7 @@ var getData = &oapispec.Route{ JSONOutputValue: func() interface{} { return core.DataArray{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetData(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).GetData(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_data_blob.go b/internal/apiserver/route_get_data_blob.go index 79e30c384b..ddf375a249 100644 --- a/internal/apiserver/route_get_data_blob.go +++ b/internal/apiserver/route_get_data_blob.go @@ -40,7 +40,8 @@ var getDataBlob = &oapispec.Route{ JSONOutputValue: func() interface{} { return []byte{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - blob, reader, err := getOr(r.Ctx).Data().DownloadBlob(r.Ctx, extractNamespace(r.PP), r.PP["dataid"]) + ns := extractNamespace(r.PP) + blob, reader, err := getOr(r.Ctx, ns).Data().DownloadBlob(r.Ctx, ns, r.PP["dataid"]) if err == nil { r.ResponseHeaders.Set(core.HTTPHeadersBlobHashSHA256, blob.Hash.String()) if blob.Size > 0 { diff --git a/internal/apiserver/route_get_data_by_id.go b/internal/apiserver/route_get_data_by_id.go index aa22d15581..ebed968163 100644 --- a/internal/apiserver/route_get_data_by_id.go +++ b/internal/apiserver/route_get_data_by_id.go @@ -38,7 +38,8 @@ var getDataByID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Data{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).GetDataByID(r.Ctx, extractNamespace(r.PP), r.PP["dataid"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).GetDataByID(r.Ctx, ns, r.PP["dataid"]) return output, err }, } diff --git a/internal/apiserver/route_get_data_msgs.go b/internal/apiserver/route_get_data_msgs.go index b8e9283c88..da223e0ce4 100644 --- a/internal/apiserver/route_get_data_msgs.go +++ b/internal/apiserver/route_get_data_msgs.go @@ -39,6 +39,7 @@ var getDataMsgs = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Message{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetMessagesForData(r.Ctx, extractNamespace(r.PP), r.PP["dataid"], r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).GetMessagesForData(r.Ctx, ns, r.PP["dataid"], r.Filter)) }, } diff --git a/internal/apiserver/route_get_datatype_by_name.go b/internal/apiserver/route_get_datatype_by_name.go index fc24a37acb..1bcafaa83b 100644 --- a/internal/apiserver/route_get_datatype_by_name.go +++ b/internal/apiserver/route_get_datatype_by_name.go @@ -39,7 +39,8 @@ var getDatatypeByName = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Datatype{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).GetDatatypeByName(r.Ctx, extractNamespace(r.PP), r.PP["name"], r.PP["version"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).GetDatatypeByName(r.Ctx, ns, r.PP["name"], r.PP["version"]) return output, err }, } diff --git a/internal/apiserver/route_get_datatypes.go b/internal/apiserver/route_get_datatypes.go index 86af5fa567..1fe836a39f 100644 --- a/internal/apiserver/route_get_datatypes.go +++ b/internal/apiserver/route_get_datatypes.go @@ -37,6 +37,7 @@ var getDatatypes = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.Datatype{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetDatatypes(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).GetDatatypes(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_event_by_id.go b/internal/apiserver/route_get_event_by_id.go index 46f25fe1eb..10825331a4 100644 --- a/internal/apiserver/route_get_event_by_id.go +++ b/internal/apiserver/route_get_event_by_id.go @@ -38,7 +38,8 @@ var getEventByID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Event{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).GetEventByID(r.Ctx, extractNamespace(r.PP), r.PP["eid"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).GetEventByID(r.Ctx, ns, r.PP["eid"]) return output, err }, } diff --git a/internal/apiserver/route_get_events.go b/internal/apiserver/route_get_events.go index dafd405f0d..2c9afdef0f 100644 --- a/internal/apiserver/route_get_events.go +++ b/internal/apiserver/route_get_events.go @@ -40,9 +40,10 @@ var getEvents = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.Event{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + ns := extractNamespace(r.PP) if strings.EqualFold(r.QP["fetchreferences"], "true") { - return filterResult(getOr(r.Ctx).GetEventsWithReferences(r.Ctx, extractNamespace(r.PP), r.Filter)) + return filterResult(getOr(r.Ctx, ns).GetEventsWithReferences(r.Ctx, ns, r.Filter)) } - return filterResult(getOr(r.Ctx).GetEvents(r.Ctx, extractNamespace(r.PP), r.Filter)) + return filterResult(getOr(r.Ctx, ns).GetEvents(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_group_by_id.go b/internal/apiserver/route_get_group_by_id.go index c3d305c9ce..87737d403a 100644 --- a/internal/apiserver/route_get_group_by_id.go +++ b/internal/apiserver/route_get_group_by_id.go @@ -38,7 +38,8 @@ var getGroupByHash = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Group{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = r.Or.PrivateMessaging().GetGroupByID(r.Ctx, r.PP["hash"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).PrivateMessaging().GetGroupByID(r.Ctx, r.PP["hash"]) return output, err }, } diff --git a/internal/apiserver/route_get_groups.go b/internal/apiserver/route_get_groups.go index e3ac00c017..a79f574b18 100644 --- a/internal/apiserver/route_get_groups.go +++ b/internal/apiserver/route_get_groups.go @@ -37,6 +37,7 @@ var getGroups = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.Group{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(r.Or.PrivateMessaging().GetGroupsNS(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).PrivateMessaging().GetGroupsNS(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_identities.go b/internal/apiserver/route_get_identities.go index 8e906ecd89..11be127af6 100644 --- a/internal/apiserver/route_get_identities.go +++ b/internal/apiserver/route_get_identities.go @@ -40,9 +40,10 @@ var getIdentities = &oapispec.Route{ JSONOutputValue: func() interface{} { return &[]*core.IdentityWithVerifiers{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + ns := extractNamespace(r.PP) if strings.EqualFold(r.QP["fetchverifiers"], "true") { - return filterResult(getOr(r.Ctx).NetworkMap().GetIdentitiesWithVerifiers(r.Ctx, extractNamespace(r.PP), r.Filter)) + return filterResult(getOr(r.Ctx, ns).NetworkMap().GetIdentitiesWithVerifiers(r.Ctx, ns, r.Filter)) } - return filterResult(getOr(r.Ctx).NetworkMap().GetIdentities(r.Ctx, extractNamespace(r.PP), r.Filter)) + return filterResult(getOr(r.Ctx, ns).NetworkMap().GetIdentities(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_identity_by_id.go b/internal/apiserver/route_get_identity_by_id.go index 32b764282f..e90b787517 100644 --- a/internal/apiserver/route_get_identity_by_id.go +++ b/internal/apiserver/route_get_identity_by_id.go @@ -40,9 +40,10 @@ var getIdentityByID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Identity{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + ns := extractNamespace(r.PP) if strings.EqualFold(r.QP["fetchverifiers"], "true") { - return getOr(r.Ctx).NetworkMap().GetIdentityByIDWithVerifiers(r.Ctx, extractNamespace(r.PP), r.PP["iid"]) + return getOr(r.Ctx, ns).NetworkMap().GetIdentityByIDWithVerifiers(r.Ctx, ns, r.PP["iid"]) } - return getOr(r.Ctx).NetworkMap().GetIdentityByID(r.Ctx, extractNamespace(r.PP), r.PP["iid"]) + return getOr(r.Ctx, ns).NetworkMap().GetIdentityByID(r.Ctx, ns, r.PP["iid"]) }, } diff --git a/internal/apiserver/route_get_identity_did.go b/internal/apiserver/route_get_identity_did.go index 9a2fac7327..e25f956791 100644 --- a/internal/apiserver/route_get_identity_did.go +++ b/internal/apiserver/route_get_identity_did.go @@ -37,6 +37,7 @@ var getIdentityDID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &networkmap.DIDDocument{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return getOr(r.Ctx).NetworkMap().GetDIDDocForIndentityByID(r.Ctx, extractNamespace(r.PP), r.PP["iid"]) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).NetworkMap().GetDIDDocForIndentityByID(r.Ctx, ns, r.PP["iid"]) }, } diff --git a/internal/apiserver/route_get_identity_verifiers.go b/internal/apiserver/route_get_identity_verifiers.go index 89960681e7..9307bab290 100644 --- a/internal/apiserver/route_get_identity_verifiers.go +++ b/internal/apiserver/route_get_identity_verifiers.go @@ -39,6 +39,7 @@ var getIdentityVerifiers = &oapispec.Route{ JSONOutputValue: func() interface{} { return &[]*core.Verifier{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).NetworkMap().GetIdentityVerifiers(r.Ctx, extractNamespace(r.PP), r.PP["iid"], r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).NetworkMap().GetIdentityVerifiers(r.Ctx, ns, r.PP["iid"], r.Filter)) }, } diff --git a/internal/apiserver/route_get_msg_by_id.go b/internal/apiserver/route_get_msg_by_id.go index c2a02b6a40..906a9973a5 100644 --- a/internal/apiserver/route_get_msg_by_id.go +++ b/internal/apiserver/route_get_msg_by_id.go @@ -41,9 +41,10 @@ var getMsgByID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.MessageInOut{} }, // can include full values JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + ns := extractNamespace(r.PP) if strings.EqualFold(r.QP["data"], "true") || strings.EqualFold(r.QP["fetchdata"], "true") { - return getOr(r.Ctx).GetMessageByIDWithData(r.Ctx, extractNamespace(r.PP), r.PP["msgid"]) + return getOr(r.Ctx, ns).GetMessageByIDWithData(r.Ctx, ns, r.PP["msgid"]) } - return getOr(r.Ctx).GetMessageByID(r.Ctx, extractNamespace(r.PP), r.PP["msgid"]) + return getOr(r.Ctx, ns).GetMessageByID(r.Ctx, ns, r.PP["msgid"]) }, } diff --git a/internal/apiserver/route_get_msg_data.go b/internal/apiserver/route_get_msg_data.go index 0adc9d12e7..1473d3069f 100644 --- a/internal/apiserver/route_get_msg_data.go +++ b/internal/apiserver/route_get_msg_data.go @@ -38,7 +38,8 @@ var getMsgData = &oapispec.Route{ JSONOutputValue: func() interface{} { return core.DataArray{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).GetMessageData(r.Ctx, extractNamespace(r.PP), r.PP["msgid"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).GetMessageData(r.Ctx, ns, r.PP["msgid"]) return output, err }, } diff --git a/internal/apiserver/route_get_msg_events.go b/internal/apiserver/route_get_msg_events.go index b597a140ae..c66c1bb07f 100644 --- a/internal/apiserver/route_get_msg_events.go +++ b/internal/apiserver/route_get_msg_events.go @@ -39,6 +39,7 @@ var getMsgEvents = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.Event{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetMessageEvents(r.Ctx, extractNamespace(r.PP), r.PP["msgid"], r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).GetMessageEvents(r.Ctx, ns, r.PP["msgid"], r.Filter)) }, } diff --git a/internal/apiserver/route_get_msg_txn.go b/internal/apiserver/route_get_msg_txn.go index f0c397f677..5bd285cb9d 100644 --- a/internal/apiserver/route_get_msg_txn.go +++ b/internal/apiserver/route_get_msg_txn.go @@ -38,7 +38,8 @@ var getMsgTxn = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Transaction{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).GetMessageTransaction(r.Ctx, extractNamespace(r.PP), r.PP["msgid"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).GetMessageTransaction(r.Ctx, ns, r.PP["msgid"]) return output, err }, } diff --git a/internal/apiserver/route_get_msgs.go b/internal/apiserver/route_get_msgs.go index 26013b7c9a..a710af348a 100644 --- a/internal/apiserver/route_get_msgs.go +++ b/internal/apiserver/route_get_msgs.go @@ -40,9 +40,10 @@ var getMsgs = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.Message{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + ns := extractNamespace(r.PP) if strings.EqualFold(r.QP["fetchdata"], "true") { - return filterResult(getOr(r.Ctx).GetMessagesWithData(r.Ctx, extractNamespace(r.PP), r.Filter)) + return filterResult(getOr(r.Ctx, ns).GetMessagesWithData(r.Ctx, ns, r.Filter)) } - return filterResult(getOr(r.Ctx).GetMessages(r.Ctx, extractNamespace(r.PP), r.Filter)) + return filterResult(getOr(r.Ctx, ns).GetMessages(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_namespace.go b/internal/apiserver/route_get_namespace.go index 0d15781b42..9ed6e2a7d1 100644 --- a/internal/apiserver/route_get_namespace.go +++ b/internal/apiserver/route_get_namespace.go @@ -39,7 +39,8 @@ var getNamespace = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Namespace{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).GetNamespace(r.Ctx, extractNamespace(r.PP)) + ns := r.PP["ns"] + output, err = getOr(r.Ctx, ns).GetNamespace(r.Ctx, ns) return output, err }, } diff --git a/internal/apiserver/route_get_namespaces.go b/internal/apiserver/route_get_namespaces.go index 05bcc505c4..6631b20978 100644 --- a/internal/apiserver/route_get_namespaces.go +++ b/internal/apiserver/route_get_namespaces.go @@ -37,6 +37,6 @@ var getNamespaces = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.Namespace{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetNamespaces(r.Ctx, r.Filter)) + return filterResult(getRootMgr(r.Ctx).GetNamespaces(r.Ctx, r.Filter)) }, } diff --git a/internal/apiserver/route_get_net_did.go b/internal/apiserver/route_get_net_did.go index 8b88f0d656..eddd5345eb 100644 --- a/internal/apiserver/route_get_net_did.go +++ b/internal/apiserver/route_get_net_did.go @@ -41,9 +41,10 @@ var getIdentityByDID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.IdentityWithVerifiers{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + ns := extractNamespace(r.PP) if strings.EqualFold(r.QP["fetchverifiers"], "true") { - return getOr(r.Ctx).NetworkMap().GetIdentityByDIDWithVerifiers(r.Ctx, r.PP["did"]) + return getOr(r.Ctx, ns).NetworkMap().GetIdentityByDIDWithVerifiers(r.Ctx, r.PP["did"]) } - return getOr(r.Ctx).NetworkMap().GetIdentityByDID(r.Ctx, r.PP["did"]) + return getOr(r.Ctx, ns).NetworkMap().GetIdentityByDID(r.Ctx, r.PP["did"]) }, } diff --git a/internal/apiserver/route_get_net_diddoc.go b/internal/apiserver/route_get_net_diddoc.go index 5efb0d3aac..4731e84d01 100644 --- a/internal/apiserver/route_get_net_diddoc.go +++ b/internal/apiserver/route_get_net_diddoc.go @@ -37,6 +37,7 @@ var getDIDDocByDID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &networkmap.DIDDocument{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return getOr(r.Ctx).NetworkMap().GetDIDDocForIndentityByDID(r.Ctx, r.PP["did"]) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).NetworkMap().GetDIDDocForIndentityByDID(r.Ctx, r.PP["did"]) }, } diff --git a/internal/apiserver/route_get_net_identities.go b/internal/apiserver/route_get_net_identities.go index 254f04e156..4655a8c122 100644 --- a/internal/apiserver/route_get_net_identities.go +++ b/internal/apiserver/route_get_net_identities.go @@ -39,9 +39,10 @@ var getNetworkIdentities = &oapispec.Route{ JSONOutputValue: func() interface{} { return &[]*core.IdentityWithVerifiers{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { + ns := extractNamespace(r.PP) if strings.EqualFold(r.QP["fetchverifiers"], "true") { - return filterResult(getOr(r.Ctx).NetworkMap().GetIdentitiesWithVerifiersGlobal(r.Ctx, r.Filter)) + return filterResult(getOr(r.Ctx, ns).NetworkMap().GetIdentitiesWithVerifiersGlobal(r.Ctx, r.Filter)) } - return filterResult(getOr(r.Ctx).NetworkMap().GetIdentitiesGlobal(r.Ctx, r.Filter)) + return filterResult(getOr(r.Ctx, ns).NetworkMap().GetIdentitiesGlobal(r.Ctx, r.Filter)) }, } diff --git a/internal/apiserver/route_get_net_node.go b/internal/apiserver/route_get_net_node.go index cc4a8e563a..026a6a07de 100644 --- a/internal/apiserver/route_get_net_node.go +++ b/internal/apiserver/route_get_net_node.go @@ -38,7 +38,8 @@ var getNetworkNode = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Identity{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).NetworkMap().GetNodeByNameOrID(r.Ctx, r.PP["nameOrId"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).NetworkMap().GetNodeByNameOrID(r.Ctx, r.PP["nameOrId"]) return output, err }, } diff --git a/internal/apiserver/route_get_net_nodes.go b/internal/apiserver/route_get_net_nodes.go index c11aad137b..9775c6cd92 100644 --- a/internal/apiserver/route_get_net_nodes.go +++ b/internal/apiserver/route_get_net_nodes.go @@ -37,6 +37,7 @@ var getNetworkNodes = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.Identity{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).NetworkMap().GetNodes(r.Ctx, r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).NetworkMap().GetNodes(r.Ctx, r.Filter)) }, } diff --git a/internal/apiserver/route_get_net_org.go b/internal/apiserver/route_get_net_org.go index 0cbff31497..8eb8c4d8a6 100644 --- a/internal/apiserver/route_get_net_org.go +++ b/internal/apiserver/route_get_net_org.go @@ -38,7 +38,8 @@ var getNetworkOrg = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Identity{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).NetworkMap().GetOrganizationByNameOrID(r.Ctx, r.PP["nameOrId"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).NetworkMap().GetOrganizationByNameOrID(r.Ctx, r.PP["nameOrId"]) return output, err }, } diff --git a/internal/apiserver/route_get_net_orgs.go b/internal/apiserver/route_get_net_orgs.go index 57710ab12a..cd00211805 100644 --- a/internal/apiserver/route_get_net_orgs.go +++ b/internal/apiserver/route_get_net_orgs.go @@ -37,6 +37,7 @@ var getNetworkOrgs = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.Identity{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).NetworkMap().GetOrganizations(r.Ctx, r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).NetworkMap().GetOrganizations(r.Ctx, r.Filter)) }, } diff --git a/internal/apiserver/route_get_op_by_id.go b/internal/apiserver/route_get_op_by_id.go index 727a137b6c..8d5549ade4 100644 --- a/internal/apiserver/route_get_op_by_id.go +++ b/internal/apiserver/route_get_op_by_id.go @@ -38,7 +38,8 @@ var getOpByID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Operation{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).GetOperationByIDNamespaced(r.Ctx, extractNamespace(r.PP), r.PP["opid"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).GetOperationByIDNamespaced(r.Ctx, ns, r.PP["opid"]) return output, err }, } diff --git a/internal/apiserver/route_get_ops.go b/internal/apiserver/route_get_ops.go index 1c3363fa90..0d9b3c71bb 100644 --- a/internal/apiserver/route_get_ops.go +++ b/internal/apiserver/route_get_ops.go @@ -37,6 +37,7 @@ var getOps = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.Operation{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetOperationsNamespaced(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).GetOperationsNamespaced(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_status.go b/internal/apiserver/route_get_status.go index c980eef27e..f00cb52f4e 100644 --- a/internal/apiserver/route_get_status.go +++ b/internal/apiserver/route_get_status.go @@ -36,7 +36,8 @@ var getStatus = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.NodeStatus{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).GetStatus(r.Ctx) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).GetStatus(r.Ctx) return output, err }, } diff --git a/internal/apiserver/route_get_subscription_by_id.go b/internal/apiserver/route_get_subscription_by_id.go index 15517e3dcd..dec83e6c04 100644 --- a/internal/apiserver/route_get_subscription_by_id.go +++ b/internal/apiserver/route_get_subscription_by_id.go @@ -38,7 +38,8 @@ var getSubscriptionByID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Subscription{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).GetSubscriptionByID(r.Ctx, extractNamespace(r.PP), r.PP["subid"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).GetSubscriptionByID(r.Ctx, ns, r.PP["subid"]) return output, err }, } diff --git a/internal/apiserver/route_get_subscriptions.go b/internal/apiserver/route_get_subscriptions.go index d4e77795bb..81a3473b2f 100644 --- a/internal/apiserver/route_get_subscriptions.go +++ b/internal/apiserver/route_get_subscriptions.go @@ -37,6 +37,7 @@ var getSubscriptions = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.Subscription{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetSubscriptions(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).GetSubscriptions(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_token_account_pools.go b/internal/apiserver/route_get_token_account_pools.go index f710a9e103..bdd9980372 100644 --- a/internal/apiserver/route_get_token_account_pools.go +++ b/internal/apiserver/route_get_token_account_pools.go @@ -39,6 +39,7 @@ var getTokenAccountPools = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.TokenAccountPool{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).Assets().GetTokenAccountPools(r.Ctx, extractNamespace(r.PP), r.PP["key"], r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).Assets().GetTokenAccountPools(r.Ctx, ns, r.PP["key"], r.Filter)) }, } diff --git a/internal/apiserver/route_get_token_accounts.go b/internal/apiserver/route_get_token_accounts.go index 7cfbd2e7aa..5b6da5accd 100644 --- a/internal/apiserver/route_get_token_accounts.go +++ b/internal/apiserver/route_get_token_accounts.go @@ -37,6 +37,7 @@ var getTokenAccounts = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.TokenAccount{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).Assets().GetTokenAccounts(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).Assets().GetTokenAccounts(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_token_approvals.go b/internal/apiserver/route_get_token_approvals.go index beaf4f326f..0e450aec72 100644 --- a/internal/apiserver/route_get_token_approvals.go +++ b/internal/apiserver/route_get_token_approvals.go @@ -37,6 +37,7 @@ var getTokenApprovals = &oapispec.Route{ JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { filter := r.Filter - return filterResult(getOr(r.Ctx).Assets().GetTokenApprovals(r.Ctx, extractNamespace(r.PP), filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).Assets().GetTokenApprovals(r.Ctx, ns, filter)) }, } diff --git a/internal/apiserver/route_get_token_balances.go b/internal/apiserver/route_get_token_balances.go index cef44536fc..ea178ac7ed 100644 --- a/internal/apiserver/route_get_token_balances.go +++ b/internal/apiserver/route_get_token_balances.go @@ -37,6 +37,7 @@ var getTokenBalances = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.TokenBalance{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).Assets().GetTokenBalances(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).Assets().GetTokenBalances(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_token_connectors.go b/internal/apiserver/route_get_token_connectors.go index 03c8fedab2..eb52b9683a 100644 --- a/internal/apiserver/route_get_token_connectors.go +++ b/internal/apiserver/route_get_token_connectors.go @@ -36,6 +36,7 @@ var getTokenConnectors = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.TokenConnector{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return getOr(r.Ctx).Assets().GetTokenConnectors(r.Ctx, extractNamespace(r.PP)), nil + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Assets().GetTokenConnectors(r.Ctx, ns), nil }, } diff --git a/internal/apiserver/route_get_token_pool_by_name_or_id.go b/internal/apiserver/route_get_token_pool_by_name_or_id.go index b147097d4f..ff86e487ea 100644 --- a/internal/apiserver/route_get_token_pool_by_name_or_id.go +++ b/internal/apiserver/route_get_token_pool_by_name_or_id.go @@ -38,7 +38,8 @@ var getTokenPoolByNameOrID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.TokenPool{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).Assets().GetTokenPoolByNameOrID(r.Ctx, extractNamespace(r.PP), r.PP["nameOrId"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).Assets().GetTokenPoolByNameOrID(r.Ctx, ns, r.PP["nameOrId"]) return output, err }, } diff --git a/internal/apiserver/route_get_token_pools.go b/internal/apiserver/route_get_token_pools.go index a075ce473c..c46eb701a7 100644 --- a/internal/apiserver/route_get_token_pools.go +++ b/internal/apiserver/route_get_token_pools.go @@ -37,6 +37,7 @@ var getTokenPools = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.TokenPool{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).Assets().GetTokenPools(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).Assets().GetTokenPools(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_token_transfer_by_id.go b/internal/apiserver/route_get_token_transfer_by_id.go index 2a1ea8c488..7a939bc975 100644 --- a/internal/apiserver/route_get_token_transfer_by_id.go +++ b/internal/apiserver/route_get_token_transfer_by_id.go @@ -38,7 +38,8 @@ var getTokenTransferByID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.TokenTransfer{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).Assets().GetTokenTransferByID(r.Ctx, extractNamespace(r.PP), r.PP["transferId"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).Assets().GetTokenTransferByID(r.Ctx, ns, r.PP["transferId"]) return output, err }, } diff --git a/internal/apiserver/route_get_token_transfers.go b/internal/apiserver/route_get_token_transfers.go index 2d70845023..98b53b5c23 100644 --- a/internal/apiserver/route_get_token_transfers.go +++ b/internal/apiserver/route_get_token_transfers.go @@ -47,6 +47,7 @@ var getTokenTransfers = &oapispec.Route{ Condition(fb.Eq("from", fromOrTo)). Condition(fb.Eq("to", fromOrTo))) } - return filterResult(getOr(r.Ctx).Assets().GetTokenTransfers(r.Ctx, extractNamespace(r.PP), filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).Assets().GetTokenTransfers(r.Ctx, ns, filter)) }, } diff --git a/internal/apiserver/route_get_txn_blockchainevents.go b/internal/apiserver/route_get_txn_blockchainevents.go index 9d958c069b..d87e790d2d 100644 --- a/internal/apiserver/route_get_txn_blockchainevents.go +++ b/internal/apiserver/route_get_txn_blockchainevents.go @@ -38,6 +38,7 @@ var getTxnBlockchainEvents = &oapispec.Route{ JSONOutputValue: func() interface{} { return &[]*core.BlockchainEvent{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetTransactionBlockchainEvents(r.Ctx, extractNamespace(r.PP), r.PP["txnid"])) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).GetTransactionBlockchainEvents(r.Ctx, ns, r.PP["txnid"])) }, } diff --git a/internal/apiserver/route_get_txn_by_id.go b/internal/apiserver/route_get_txn_by_id.go index 30ce579fc7..e63ce340cf 100644 --- a/internal/apiserver/route_get_txn_by_id.go +++ b/internal/apiserver/route_get_txn_by_id.go @@ -39,7 +39,8 @@ var getTxnByID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Transaction{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).GetTransactionByID(r.Ctx, extractNamespace(r.PP), r.PP["txnid"]) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).GetTransactionByID(r.Ctx, ns, r.PP["txnid"]) return output, err }, } diff --git a/internal/apiserver/route_get_txn_ops.go b/internal/apiserver/route_get_txn_ops.go index a3cc498a5b..f76ba8633a 100644 --- a/internal/apiserver/route_get_txn_ops.go +++ b/internal/apiserver/route_get_txn_ops.go @@ -38,6 +38,7 @@ var getTxnOps = &oapispec.Route{ JSONOutputValue: func() interface{} { return &[]*core.Operation{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetTransactionOperations(r.Ctx, extractNamespace(r.PP), r.PP["txnid"])) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).GetTransactionOperations(r.Ctx, ns, r.PP["txnid"])) }, } diff --git a/internal/apiserver/route_get_txn_status.go b/internal/apiserver/route_get_txn_status.go index ffbb7504d8..dbb39e6c14 100644 --- a/internal/apiserver/route_get_txn_status.go +++ b/internal/apiserver/route_get_txn_status.go @@ -38,6 +38,7 @@ var getTxnStatus = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.TransactionStatus{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return getOr(r.Ctx).GetTransactionStatus(r.Ctx, extractNamespace(r.PP), r.PP["txnid"]) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).GetTransactionStatus(r.Ctx, ns, r.PP["txnid"]) }, } diff --git a/internal/apiserver/route_get_txns.go b/internal/apiserver/route_get_txns.go index 4506cf49f6..849ae2cc92 100644 --- a/internal/apiserver/route_get_txns.go +++ b/internal/apiserver/route_get_txns.go @@ -37,6 +37,7 @@ var getTxns = &oapispec.Route{ JSONOutputValue: func() interface{} { return []*core.Transaction{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetTransactions(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).GetTransactions(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_get_verifier_by_id.go b/internal/apiserver/route_get_verifier_by_id.go index f45440e330..18d74565da 100644 --- a/internal/apiserver/route_get_verifier_by_id.go +++ b/internal/apiserver/route_get_verifier_by_id.go @@ -37,6 +37,7 @@ var getVerifierByID = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Verifier{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return getOr(r.Ctx).NetworkMap().GetVerifierByHash(r.Ctx, extractNamespace(r.PP), r.PP["hash"]) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).NetworkMap().GetVerifierByHash(r.Ctx, ns, r.PP["hash"]) }, } diff --git a/internal/apiserver/route_get_verifiers.go b/internal/apiserver/route_get_verifiers.go index 1f25d3a593..b4c6f2d16e 100644 --- a/internal/apiserver/route_get_verifiers.go +++ b/internal/apiserver/route_get_verifiers.go @@ -37,6 +37,7 @@ var getVerifiers = &oapispec.Route{ JSONOutputValue: func() interface{} { return &[]*core.Verifier{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).NetworkMap().GetVerifiers(r.Ctx, extractNamespace(r.PP), r.Filter)) + ns := extractNamespace(r.PP) + return filterResult(getOr(r.Ctx, ns).NetworkMap().GetVerifiers(r.Ctx, ns, r.Filter)) }, } diff --git a/internal/apiserver/route_patch_update_identity.go b/internal/apiserver/route_patch_update_identity.go index 4e2e753d75..67822655d8 100644 --- a/internal/apiserver/route_patch_update_identity.go +++ b/internal/apiserver/route_patch_update_identity.go @@ -43,7 +43,8 @@ var patchUpdateIdentity = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - org, err := getOr(r.Ctx).NetworkMap().UpdateIdentity(r.Ctx, extractNamespace(r.PP), r.PP["iid"], r.Input.(*core.IdentityUpdateDTO), waitConfirm) + ns := extractNamespace(r.PP) + org, err := getOr(r.Ctx, ns).NetworkMap().UpdateIdentity(r.Ctx, ns, r.PP["iid"], r.Input.(*core.IdentityUpdateDTO), waitConfirm) return org, err }, } diff --git a/internal/apiserver/route_post_contract_api_invoke.go b/internal/apiserver/route_post_contract_api_invoke.go index f0ff048a6b..990ac4a327 100644 --- a/internal/apiserver/route_post_contract_api_invoke.go +++ b/internal/apiserver/route_post_contract_api_invoke.go @@ -46,6 +46,7 @@ var postContractAPIInvoke = &oapispec.Route{ r.SuccessStatus = syncRetcode(waitConfirm) req := r.Input.(*core.ContractCallRequest) req.Type = core.CallTypeInvoke - return getOr(r.Ctx).Contracts().InvokeContractAPI(r.Ctx, extractNamespace(r.PP), r.PP["apiName"], r.PP["methodPath"], req, waitConfirm) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Contracts().InvokeContractAPI(r.Ctx, ns, r.PP["apiName"], r.PP["methodPath"], req, waitConfirm) }, } diff --git a/internal/apiserver/route_post_contract_api_listeners.go b/internal/apiserver/route_post_contract_api_listeners.go index 2c9757d9b7..1147b72bde 100644 --- a/internal/apiserver/route_post_contract_api_listeners.go +++ b/internal/apiserver/route_post_contract_api_listeners.go @@ -39,6 +39,7 @@ var postContractAPIListeners = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.ContractListener{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return getOr(r.Ctx).Contracts().AddContractAPIListener(r.Ctx, extractNamespace(r.PP), r.PP["apiName"], r.PP["eventPath"], r.Input.(*core.ContractListener)) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Contracts().AddContractAPIListener(r.Ctx, ns, r.PP["apiName"], r.PP["eventPath"], r.Input.(*core.ContractListener)) }, } diff --git a/internal/apiserver/route_post_contract_api_query.go b/internal/apiserver/route_post_contract_api_query.go index ecf10db2a4..95eb6b74e1 100644 --- a/internal/apiserver/route_post_contract_api_query.go +++ b/internal/apiserver/route_post_contract_api_query.go @@ -41,6 +41,7 @@ var postContractAPIQuery = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { req := r.Input.(*core.ContractCallRequest) req.Type = core.CallTypeQuery - return getOr(r.Ctx).Contracts().InvokeContractAPI(r.Ctx, extractNamespace(r.PP), r.PP["apiName"], r.PP["methodPath"], req, true) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Contracts().InvokeContractAPI(r.Ctx, ns, r.PP["apiName"], r.PP["methodPath"], req, true) }, } diff --git a/internal/apiserver/route_post_contract_interface_generate.go b/internal/apiserver/route_post_contract_interface_generate.go index c5327ac927..40f714e973 100644 --- a/internal/apiserver/route_post_contract_interface_generate.go +++ b/internal/apiserver/route_post_contract_interface_generate.go @@ -37,6 +37,7 @@ var postContractInterfaceGenerate = &oapispec.Route{ JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { generationRequest := r.Input.(*core.FFIGenerationRequest) - return getOr(r.Ctx).Contracts().GenerateFFI(r.Ctx, extractNamespace(r.PP), generationRequest) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Contracts().GenerateFFI(r.Ctx, ns, generationRequest) }, } diff --git a/internal/apiserver/route_post_contract_invoke.go b/internal/apiserver/route_post_contract_invoke.go index e140cc5948..05e1ca253a 100644 --- a/internal/apiserver/route_post_contract_invoke.go +++ b/internal/apiserver/route_post_contract_invoke.go @@ -43,6 +43,7 @@ var postContractInvoke = &oapispec.Route{ r.SuccessStatus = syncRetcode(waitConfirm) req := r.Input.(*core.ContractCallRequest) req.Type = core.CallTypeInvoke - return getOr(r.Ctx).Contracts().InvokeContract(r.Ctx, extractNamespace(r.PP), req, waitConfirm) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Contracts().InvokeContract(r.Ctx, ns, req, waitConfirm) }, } diff --git a/internal/apiserver/route_post_contract_query.go b/internal/apiserver/route_post_contract_query.go index 3774a723bf..dbb1c7702e 100644 --- a/internal/apiserver/route_post_contract_query.go +++ b/internal/apiserver/route_post_contract_query.go @@ -38,6 +38,7 @@ var postContractQuery = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { req := r.Input.(*core.ContractCallRequest) req.Type = core.CallTypeQuery - return getOr(r.Ctx).Contracts().InvokeContract(r.Ctx, extractNamespace(r.PP), req, true) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Contracts().InvokeContract(r.Ctx, ns, req, true) }, } diff --git a/internal/apiserver/route_post_data.go b/internal/apiserver/route_post_data.go index 1e2a7fab61..f8985cd2ed 100644 --- a/internal/apiserver/route_post_data.go +++ b/internal/apiserver/route_post_data.go @@ -47,7 +47,8 @@ var postData = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Data{} }, JSONOutputCodes: []int{http.StatusCreated}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).Data().UploadJSON(r.Ctx, extractNamespace(r.PP), r.Input.(*core.DataRefOrValue)) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).Data().UploadJSON(r.Ctx, ns, r.Input.(*core.DataRefOrValue)) return output, err }, FormUploadHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { @@ -71,7 +72,8 @@ var postData = &oapispec.Route{ } data.Value = fftypes.JSONAnyPtr(metadata) } - output, err = getOr(r.Ctx).Data().UploadBlob(r.Ctx, extractNamespace(r.PP), data, r.Part, strings.EqualFold(r.FP["autometa"], "true")) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).Data().UploadBlob(r.Ctx, ns, data, r.Part, strings.EqualFold(r.FP["autometa"], "true")) return output, err }, } diff --git a/internal/apiserver/route_post_network_action.go b/internal/apiserver/route_post_network_action.go index 02b22e320e..865f184b33 100644 --- a/internal/apiserver/route_post_network_action.go +++ b/internal/apiserver/route_post_network_action.go @@ -36,7 +36,8 @@ var postNetworkAction = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.NetworkAction{} }, JSONOutputCodes: []int{http.StatusAccepted}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - err = getOr(r.Ctx).SubmitNetworkAction(r.Ctx, r.Input.(*core.NetworkAction)) + ns := extractNamespace(r.PP) + err = getOr(r.Ctx, ns).SubmitNetworkAction(r.Ctx, r.Input.(*core.NetworkAction)) return r.Input, err }, } diff --git a/internal/apiserver/route_post_new_contract_api.go b/internal/apiserver/route_post_new_contract_api.go index 7fa58ebfca..ed07dd59dc 100644 --- a/internal/apiserver/route_post_new_contract_api.go +++ b/internal/apiserver/route_post_new_contract_api.go @@ -41,6 +41,7 @@ var postNewContractAPI = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - return getOr(r.Ctx).Contracts().BroadcastContractAPI(r.Ctx, r.APIBaseURL, extractNamespace(r.PP), r.Input.(*core.ContractAPI), waitConfirm) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Contracts().BroadcastContractAPI(r.Ctx, r.APIBaseURL, extractNamespace(r.PP), r.Input.(*core.ContractAPI), waitConfirm) }, } diff --git a/internal/apiserver/route_post_new_contract_interface.go b/internal/apiserver/route_post_new_contract_interface.go index b0b115f840..ee3e79b5c9 100644 --- a/internal/apiserver/route_post_new_contract_interface.go +++ b/internal/apiserver/route_post_new_contract_interface.go @@ -41,6 +41,7 @@ var postNewContractInterface = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - return getOr(r.Ctx).Contracts().BroadcastFFI(r.Ctx, extractNamespace(r.PP), r.Input.(*core.FFI), waitConfirm) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Contracts().BroadcastFFI(r.Ctx, ns, r.Input.(*core.FFI), waitConfirm) }, } diff --git a/internal/apiserver/route_post_new_contract_listener.go b/internal/apiserver/route_post_new_contract_listener.go index 0f9dfde6fe..b97040c067 100644 --- a/internal/apiserver/route_post_new_contract_listener.go +++ b/internal/apiserver/route_post_new_contract_listener.go @@ -36,6 +36,7 @@ var postNewContractListener = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.ContractListener{} }, JSONOutputCodes: []int{http.StatusOK}, JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return getOr(r.Ctx).Contracts().AddContractListener(r.Ctx, extractNamespace(r.PP), r.Input.(*core.ContractListenerInput)) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Contracts().AddContractListener(r.Ctx, ns, r.Input.(*core.ContractListenerInput)) }, } diff --git a/internal/apiserver/route_post_new_datatype.go b/internal/apiserver/route_post_new_datatype.go index 2da2a0d248..7df390ee18 100644 --- a/internal/apiserver/route_post_new_datatype.go +++ b/internal/apiserver/route_post_new_datatype.go @@ -41,7 +41,8 @@ var postNewDatatype = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - _, err = getOr(r.Ctx).Broadcast().BroadcastDatatype(r.Ctx, extractNamespace(r.PP), r.Input.(*core.Datatype), waitConfirm) + ns := extractNamespace(r.PP) + _, err = getOr(r.Ctx, ns).Broadcast().BroadcastDatatype(r.Ctx, ns, r.Input.(*core.Datatype), waitConfirm) return r.Input, err }, } diff --git a/internal/apiserver/route_post_new_identity.go b/internal/apiserver/route_post_new_identity.go index ff36911802..224dd67379 100644 --- a/internal/apiserver/route_post_new_identity.go +++ b/internal/apiserver/route_post_new_identity.go @@ -41,7 +41,8 @@ var postNewIdentity = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - org, err := getOr(r.Ctx).NetworkMap().RegisterIdentity(r.Ctx, extractNamespace(r.PP), r.Input.(*core.IdentityCreateDTO), waitConfirm) + ns := extractNamespace(r.PP) + org, err := getOr(r.Ctx, ns).NetworkMap().RegisterIdentity(r.Ctx, ns, r.Input.(*core.IdentityCreateDTO), waitConfirm) return org, err }, } diff --git a/internal/apiserver/route_post_new_message_broadcast.go b/internal/apiserver/route_post_new_message_broadcast.go index 118ce2eebf..a459eac409 100644 --- a/internal/apiserver/route_post_new_message_broadcast.go +++ b/internal/apiserver/route_post_new_message_broadcast.go @@ -41,7 +41,8 @@ var postNewMessageBroadcast = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - output, err = getOr(r.Ctx).Broadcast().BroadcastMessage(r.Ctx, extractNamespace(r.PP), r.Input.(*core.MessageInOut), waitConfirm) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).Broadcast().BroadcastMessage(r.Ctx, ns, r.Input.(*core.MessageInOut), waitConfirm) return output, err }, } diff --git a/internal/apiserver/route_post_new_message_private.go b/internal/apiserver/route_post_new_message_private.go index 06472a35db..d02f0ddc29 100644 --- a/internal/apiserver/route_post_new_message_private.go +++ b/internal/apiserver/route_post_new_message_private.go @@ -41,7 +41,8 @@ var postNewMessagePrivate = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - output, err = getOr(r.Ctx).PrivateMessaging().SendMessage(r.Ctx, extractNamespace(r.PP), r.Input.(*core.MessageInOut), waitConfirm) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).PrivateMessaging().SendMessage(r.Ctx, ns, r.Input.(*core.MessageInOut), waitConfirm) return output, err }, } diff --git a/internal/apiserver/route_post_new_message_requestreply.go b/internal/apiserver/route_post_new_message_requestreply.go index bd28208387..13a3d915b0 100644 --- a/internal/apiserver/route_post_new_message_requestreply.go +++ b/internal/apiserver/route_post_new_message_requestreply.go @@ -36,7 +36,8 @@ var postNewMessageRequestReply = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.MessageInOut{} }, JSONOutputCodes: []int{http.StatusOK}, // Sync operation JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).RequestReply(r.Ctx, extractNamespace(r.PP), r.Input.(*core.MessageInOut)) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).RequestReply(r.Ctx, ns, r.Input.(*core.MessageInOut)) return output, err }, } diff --git a/internal/apiserver/route_post_new_namespace.go b/internal/apiserver/route_post_new_namespace.go deleted file mode 100644 index 2a2d6ec8d4..0000000000 --- a/internal/apiserver/route_post_new_namespace.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright © 2022 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" - "strings" - - "github.com/hyperledger/firefly/internal/coremsgs" - "github.com/hyperledger/firefly/internal/oapispec" - "github.com/hyperledger/firefly/pkg/core" -) - -var postNewNamespace = &oapispec.Route{ - Name: "postNewNamespace", - Path: "namespaces", - Method: http.MethodPost, - QueryParams: []*oapispec.QueryParam{ - {Name: "confirm", Description: coremsgs.APIConfirmQueryParam, IsBool: true, Example: "true"}, - }, - FilterFactory: nil, - Description: coremsgs.APIEndpointsPostNewNamespace, - JSONInputValue: func() interface{} { return &core.Namespace{} }, - JSONOutputValue: func() interface{} { return &core.Namespace{} }, - JSONOutputCodes: []int{http.StatusAccepted, http.StatusOK}, - JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - waitConfirm := strings.EqualFold(r.QP["confirm"], "true") - r.SuccessStatus = syncRetcode(waitConfirm) - _, err = getOr(r.Ctx).Broadcast().BroadcastNamespace(r.Ctx, r.Input.(*core.Namespace), waitConfirm) - return r.Input, err - }, -} diff --git a/internal/apiserver/route_post_new_namespace_test.go b/internal/apiserver/route_post_new_namespace_test.go deleted file mode 100644 index 64a07e87cf..0000000000 --- a/internal/apiserver/route_post_new_namespace_test.go +++ /dev/null @@ -1,65 +0,0 @@ -// 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 ( - "bytes" - "encoding/json" - "net/http/httptest" - "testing" - - "github.com/hyperledger/firefly/mocks/broadcastmocks" - "github.com/hyperledger/firefly/pkg/core" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestPostNewNamespace(t *testing.T) { - o, r := newTestAPIServer() - mbm := &broadcastmocks.Manager{} - o.On("Broadcast").Return(mbm) - input := core.Namespace{} - var buf bytes.Buffer - json.NewEncoder(&buf).Encode(&input) - req := httptest.NewRequest("POST", "/api/v1/namespaces", &buf) - req.Header.Set("Content-Type", "application/json; charset=utf-8") - res := httptest.NewRecorder() - - mbm.On("BroadcastNamespace", mock.Anything, mock.AnythingOfType("*core.Namespace"), false). - Return(&core.Message{}, nil) - r.ServeHTTP(res, req) - - assert.Equal(t, 202, res.Result().StatusCode) -} - -func TestPostNewNamespaceSync(t *testing.T) { - o, r := newTestAPIServer() - mbm := &broadcastmocks.Manager{} - o.On("Broadcast").Return(mbm) - input := core.Namespace{} - var buf bytes.Buffer - json.NewEncoder(&buf).Encode(&input) - req := httptest.NewRequest("POST", "/api/v1/namespaces?confirm", &buf) - req.Header.Set("Content-Type", "application/json; charset=utf-8") - res := httptest.NewRecorder() - - mbm.On("BroadcastNamespace", mock.Anything, mock.AnythingOfType("*core.Namespace"), true). - Return(&core.Message{}, nil) - r.ServeHTTP(res, req) - - assert.Equal(t, 200, res.Result().StatusCode) -} diff --git a/internal/apiserver/route_post_new_node_self.go b/internal/apiserver/route_post_new_node_self.go index 008da7e704..58b314ba4e 100644 --- a/internal/apiserver/route_post_new_node_self.go +++ b/internal/apiserver/route_post_new_node_self.go @@ -41,7 +41,8 @@ var postNodesSelf = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - node, err := getOr(r.Ctx).NetworkMap().RegisterNode(r.Ctx, waitConfirm) + ns := extractNamespace(r.PP) + node, err := getOr(r.Ctx, ns).NetworkMap().RegisterNode(r.Ctx, waitConfirm) return node, err }, } diff --git a/internal/apiserver/route_post_new_organization.go b/internal/apiserver/route_post_new_organization.go index 394c24da0d..8352dd2d28 100644 --- a/internal/apiserver/route_post_new_organization.go +++ b/internal/apiserver/route_post_new_organization.go @@ -41,7 +41,8 @@ var postNewOrganization = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - _, err = getOr(r.Ctx).NetworkMap().RegisterOrganization(r.Ctx, r.Input.(*core.IdentityCreateDTO), waitConfirm) + ns := extractNamespace(r.PP) + _, err = getOr(r.Ctx, ns).NetworkMap().RegisterOrganization(r.Ctx, r.Input.(*core.IdentityCreateDTO), waitConfirm) return r.Input, err }, } diff --git a/internal/apiserver/route_post_new_organization_self.go b/internal/apiserver/route_post_new_organization_self.go index 2b212e62a5..69c2e87a78 100644 --- a/internal/apiserver/route_post_new_organization_self.go +++ b/internal/apiserver/route_post_new_organization_self.go @@ -41,7 +41,8 @@ var postNewOrganizationSelf = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - org, err := getOr(r.Ctx).NetworkMap().RegisterNodeOrganization(r.Ctx, waitConfirm) + ns := extractNamespace(r.PP) + org, err := getOr(r.Ctx, ns).NetworkMap().RegisterNodeOrganization(r.Ctx, waitConfirm) return org, err }, } diff --git a/internal/apiserver/route_post_new_subscription.go b/internal/apiserver/route_post_new_subscription.go index 31efbfeb5f..237166a371 100644 --- a/internal/apiserver/route_post_new_subscription.go +++ b/internal/apiserver/route_post_new_subscription.go @@ -36,7 +36,8 @@ var postNewSubscription = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Subscription{} }, JSONOutputCodes: []int{http.StatusCreated}, // Sync operation JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).CreateSubscription(r.Ctx, extractNamespace(r.PP), r.Input.(*core.Subscription)) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).CreateSubscription(r.Ctx, ns, r.Input.(*core.Subscription)) return output, err }, } diff --git a/internal/apiserver/route_post_op_retry.go b/internal/apiserver/route_post_op_retry.go index eb6fd6d8f4..b992c1e597 100644 --- a/internal/apiserver/route_post_op_retry.go +++ b/internal/apiserver/route_post_op_retry.go @@ -43,6 +43,7 @@ var postOpRetry = &oapispec.Route{ if err != nil { return nil, err } - return getOr(r.Ctx).Operations().RetryOperation(r.Ctx, extractNamespace(r.PP), opid) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Operations().RetryOperation(r.Ctx, ns, opid) }, } diff --git a/internal/apiserver/route_post_token_approval.go b/internal/apiserver/route_post_token_approval.go index 5e3263114e..ba47fe8648 100644 --- a/internal/apiserver/route_post_token_approval.go +++ b/internal/apiserver/route_post_token_approval.go @@ -47,6 +47,7 @@ var postTokenApproval = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - return getOr(r.Ctx).Assets().TokenApproval(r.Ctx, extractNamespace(r.PP), r.Input.(*core.TokenApprovalInput), waitConfirm) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Assets().TokenApproval(r.Ctx, ns, r.Input.(*core.TokenApprovalInput), waitConfirm) }, } diff --git a/internal/apiserver/route_post_token_burn.go b/internal/apiserver/route_post_token_burn.go index 5c6646a45c..ddce9a8489 100644 --- a/internal/apiserver/route_post_token_burn.go +++ b/internal/apiserver/route_post_token_burn.go @@ -41,6 +41,7 @@ var postTokenBurn = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - return getOr(r.Ctx).Assets().BurnTokens(r.Ctx, extractNamespace(r.PP), r.Input.(*core.TokenTransferInput), waitConfirm) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Assets().BurnTokens(r.Ctx, ns, r.Input.(*core.TokenTransferInput), waitConfirm) }, } diff --git a/internal/apiserver/route_post_token_mint.go b/internal/apiserver/route_post_token_mint.go index 04c6000dae..135e1fa2ec 100644 --- a/internal/apiserver/route_post_token_mint.go +++ b/internal/apiserver/route_post_token_mint.go @@ -41,6 +41,7 @@ var postTokenMint = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - return getOr(r.Ctx).Assets().MintTokens(r.Ctx, extractNamespace(r.PP), r.Input.(*core.TokenTransferInput), waitConfirm) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Assets().MintTokens(r.Ctx, ns, r.Input.(*core.TokenTransferInput), waitConfirm) }, } diff --git a/internal/apiserver/route_post_token_pool.go b/internal/apiserver/route_post_token_pool.go index 6d39872510..2c81c304b2 100644 --- a/internal/apiserver/route_post_token_pool.go +++ b/internal/apiserver/route_post_token_pool.go @@ -41,6 +41,7 @@ var postTokenPool = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - return getOr(r.Ctx).Assets().CreateTokenPool(r.Ctx, extractNamespace(r.PP), r.Input.(*core.TokenPool), waitConfirm) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Assets().CreateTokenPool(r.Ctx, ns, r.Input.(*core.TokenPool), waitConfirm) }, } diff --git a/internal/apiserver/route_post_token_transfer.go b/internal/apiserver/route_post_token_transfer.go index 584a07d55f..4458def129 100644 --- a/internal/apiserver/route_post_token_transfer.go +++ b/internal/apiserver/route_post_token_transfer.go @@ -41,6 +41,7 @@ var postTokenTransfer = &oapispec.Route{ JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { waitConfirm := strings.EqualFold(r.QP["confirm"], "true") r.SuccessStatus = syncRetcode(waitConfirm) - return getOr(r.Ctx).Assets().TransferTokens(r.Ctx, extractNamespace(r.PP), r.Input.(*core.TokenTransferInput), waitConfirm) + ns := extractNamespace(r.PP) + return getOr(r.Ctx, ns).Assets().TransferTokens(r.Ctx, ns, r.Input.(*core.TokenTransferInput), waitConfirm) }, } diff --git a/internal/apiserver/route_put_contract_api.go b/internal/apiserver/route_put_contract_api.go index fabc279219..c9649d602e 100644 --- a/internal/apiserver/route_put_contract_api.go +++ b/internal/apiserver/route_put_contract_api.go @@ -46,9 +46,10 @@ var putContractAPI = &oapispec.Route{ r.SuccessStatus = syncRetcode(waitConfirm) api := r.Input.(*core.ContractAPI) api.ID, err = fftypes.ParseUUID(r.Ctx, r.PP["id"]) + ns := extractNamespace(r.PP) var res interface{} if err == nil { - res, err = getOr(r.Ctx).Contracts().BroadcastContractAPI(r.Ctx, r.APIBaseURL, extractNamespace(r.PP), api, waitConfirm) + res, err = getOr(r.Ctx, ns).Contracts().BroadcastContractAPI(r.Ctx, r.APIBaseURL, extractNamespace(r.PP), api, waitConfirm) } return res, err }, diff --git a/internal/apiserver/route_put_subscription.go b/internal/apiserver/route_put_subscription.go index b3cafdb942..de2fe76a3e 100644 --- a/internal/apiserver/route_put_subscription.go +++ b/internal/apiserver/route_put_subscription.go @@ -36,7 +36,8 @@ var putSubscription = &oapispec.Route{ JSONOutputValue: func() interface{} { return &core.Subscription{} }, JSONOutputCodes: []int{http.StatusOK}, // Sync operation JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).CreateUpdateSubscription(r.Ctx, extractNamespace(r.PP), r.Input.(*core.Subscription)) + ns := extractNamespace(r.PP) + output, err = getOr(r.Ctx, ns).CreateUpdateSubscription(r.Ctx, ns, r.Input.(*core.Subscription)) return output, err }, } diff --git a/internal/apiserver/routes.go b/internal/apiserver/routes.go index cc7e18effb..17cad4293d 100644 --- a/internal/apiserver/routes.go +++ b/internal/apiserver/routes.go @@ -39,7 +39,6 @@ var routes = append( getStatusPins, getStatusWebSockets, postNetworkAction, - postNewNamespace, postNewOrganization, postNewOrganizationSelf, postNodesSelf, diff --git a/internal/apiserver/server.go b/internal/apiserver/server.go index 18f3535e32..7f0e3f94cc 100644 --- a/internal/apiserver/server.go +++ b/internal/apiserver/server.go @@ -33,6 +33,7 @@ import ( "github.com/hyperledger/firefly/internal/coreconfig" "github.com/hyperledger/firefly/internal/coremsgs" "github.com/hyperledger/firefly/internal/metrics" + "github.com/hyperledger/firefly/internal/namespace" "github.com/hyperledger/firefly/internal/oapiffi" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -52,7 +53,7 @@ import ( "github.com/hyperledger/firefly/pkg/database" ) -type orchestratorContextKey struct{} +type rootManagerContextKey struct{} var ffcodeExtractor = regexp.MustCompile(`^(FF\d+):`) @@ -65,7 +66,7 @@ var ( // Server is the external interface for the API Server type Server interface { - Serve(ctx context.Context, o orchestrator.Orchestrator) error + Serve(ctx context.Context, mgr namespace.Manager) error } type apiServer struct { @@ -99,24 +100,28 @@ func NewAPIServer() Server { } } -func getOr(ctx context.Context) orchestrator.Orchestrator { - return ctx.Value(orchestratorContextKey{}).(orchestrator.Orchestrator) +func getRootMgr(ctx context.Context) namespace.Manager { + return ctx.Value(rootManagerContextKey{}).(namespace.Manager) +} + +func getOr(ctx context.Context, ns string) orchestrator.Orchestrator { + return getRootMgr(ctx).Orchestrator(ns) } // Serve is the main entry point for the API Server -func (as *apiServer) Serve(ctx context.Context, o orchestrator.Orchestrator) (err error) { +func (as *apiServer) Serve(ctx context.Context, mgr namespace.Manager) (err error) { httpErrChan := make(chan error) adminErrChan := make(chan error) metricsErrChan := make(chan error) - apiHTTPServer, err := httpserver.NewHTTPServer(ctx, "api", as.createMuxRouter(ctx, o), httpErrChan, apiConfig, corsConfig) + apiHTTPServer, err := httpserver.NewHTTPServer(ctx, "api", as.createMuxRouter(ctx, mgr), httpErrChan, apiConfig, corsConfig) if err != nil { return err } go apiHTTPServer.ServeHTTP(ctx) if config.GetBool(coreconfig.AdminEnabled) { - adminHTTPServer, err := httpserver.NewHTTPServer(ctx, "admin", as.createAdminMuxRouter(o), adminErrChan, adminConfig, corsConfig) + adminHTTPServer, err := httpserver.NewHTTPServer(ctx, "admin", as.createAdminMuxRouter(mgr), adminErrChan, adminConfig, corsConfig) if err != nil { return err } @@ -211,7 +216,7 @@ func (as *apiServer) getParams(req *http.Request, route *oapispec.Route) (queryP return queryParams, pathParams } -func (as *apiServer) routeHandler(o orchestrator.Orchestrator, apiBaseURL string, route *oapispec.Route) http.HandlerFunc { +func (as *apiServer) routeHandler(mgr namespace.Manager, apiBaseURL string, route *oapispec.Route) http.HandlerFunc { // Check the mandatory parts are ok at startup time return as.apiWrapper(func(res http.ResponseWriter, req *http.Request) (int, error) { @@ -251,10 +256,10 @@ func (as *apiServer) routeHandler(o orchestrator.Orchestrator, apiBaseURL string } if err == nil { - rCtx := context.WithValue(req.Context(), orchestratorContextKey{}, o) + rCtx := context.WithValue(req.Context(), rootManagerContextKey{}, mgr) r := &oapispec.APIRequest{ Ctx: rCtx, - Or: o, + RootMgr: mgr, Req: req, PP: pathParams, QP: queryParams, @@ -467,10 +472,10 @@ func (as *apiServer) swaggerGenerator(routes []*oapispec.Route, apiBaseURL strin } } -func (as *apiServer) contractSwaggerGenerator(o orchestrator.Orchestrator, apiBaseURL string) func(req *http.Request) (*openapi3.T, error) { +func (as *apiServer) contractSwaggerGenerator(apiBaseURL string) func(req *http.Request) (*openapi3.T, error) { return func(req *http.Request) (*openapi3.T, error) { - cm := o.Contracts() vars := mux.Vars(req) + cm := getOr(req.Context(), vars["ns"]).Contracts() api, err := cm.GetContractAPI(req.Context(), apiBaseURL, vars["ns"], vars["apiName"]) if err != nil { return nil, err @@ -488,7 +493,7 @@ func (as *apiServer) contractSwaggerGenerator(o orchestrator.Orchestrator, apiBa } } -func (as *apiServer) createMuxRouter(ctx context.Context, o orchestrator.Orchestrator) *mux.Router { +func (as *apiServer) createMuxRouter(ctx context.Context, mgr namespace.Manager) *mux.Router { r := mux.NewRouter() if as.metricsEnabled { @@ -499,12 +504,12 @@ func (as *apiServer) createMuxRouter(ctx context.Context, o orchestrator.Orchest apiBaseURL := fmt.Sprintf("%s/api/v1", publicURL) for _, route := range routes { if route.JSONHandler != nil { - r.HandleFunc(fmt.Sprintf("/api/v1/%s", route.Path), as.routeHandler(o, apiBaseURL, route)). + r.HandleFunc(fmt.Sprintf("/api/v1/%s", route.Path), as.routeHandler(mgr, apiBaseURL, route)). Methods(route.Method) } } - r.HandleFunc(`/api/v1/namespaces/{ns}/apis/{apiName}/api/swagger{ext:\.yaml|\.json|}`, as.apiWrapper(as.swaggerHandler(as.contractSwaggerGenerator(o, apiBaseURL)))) + r.HandleFunc(`/api/v1/namespaces/{ns}/apis/{apiName}/api/swagger{ext:\.yaml|\.json|}`, as.apiWrapper(as.swaggerHandler(as.contractSwaggerGenerator(apiBaseURL)))) r.HandleFunc(`/api/v1/namespaces/{ns}/apis/{apiName}/api`, func(rw http.ResponseWriter, req *http.Request) { url := req.URL.String() + "/swagger.yaml" handler := as.apiWrapper(as.swaggerUIHandler(url)) @@ -527,14 +532,14 @@ func (as *apiServer) createMuxRouter(ctx context.Context, o orchestrator.Orchest return r } -func (as *apiServer) adminWSHandler(o orchestrator.Orchestrator) http.HandlerFunc { +func (as *apiServer) adminWSHandler(mgr namespace.Manager) http.HandlerFunc { // The admin events listener will be initialized when we start, so we access it it from Orchestrator on demand return func(w http.ResponseWriter, r *http.Request) { - o.AdminEvents().ServeHTTPWebSocketListener(w, r) + // o.AdminEvents().ServeHTTPWebSocketListener(w, r) } } -func (as *apiServer) createAdminMuxRouter(o orchestrator.Orchestrator) *mux.Router { +func (as *apiServer) createAdminMuxRouter(mgr namespace.Manager) *mux.Router { r := mux.NewRouter() if as.metricsEnabled { r.Use(metrics.GetAdminServerInstrumentation().Middleware) @@ -544,7 +549,7 @@ func (as *apiServer) createAdminMuxRouter(o orchestrator.Orchestrator) *mux.Rout apiBaseURL := fmt.Sprintf("%s/admin/api/v1", publicURL) for _, route := range adminRoutes { if route.JSONHandler != nil { - r.HandleFunc(fmt.Sprintf("/admin/api/v1/%s", route.Path), as.routeHandler(o, apiBaseURL, route)). + r.HandleFunc(fmt.Sprintf("/admin/api/v1/%s", route.Path), as.routeHandler(mgr, apiBaseURL, route)). Methods(route.Method) } } @@ -552,7 +557,7 @@ func (as *apiServer) createAdminMuxRouter(o orchestrator.Orchestrator) *mux.Rout r.HandleFunc(`/admin/api`, as.apiWrapper(as.swaggerUIHandler(publicURL+"/api/swagger.yaml"))) r.HandleFunc(`/favicon{any:.*}.png`, favIcons) - r.HandleFunc(`/admin/ws`, as.adminWSHandler(o)) + r.HandleFunc(`/admin/ws`, as.adminWSHandler(mgr)) return r } diff --git a/internal/identity/identitymanager.go b/internal/identity/identitymanager.go index a61e666b5e..9ea899543b 100644 --- a/internal/identity/identitymanager.go +++ b/internal/identity/identitymanager.go @@ -58,7 +58,7 @@ type Manager interface { type identityManager struct { database database.Plugin - plugin map[string]identity.Plugin + plugin identity.Plugin blockchain blockchain.Plugin data data.Manager @@ -70,7 +70,7 @@ type identityManager struct { signingKeyCache *ccache.Cache } -func NewIdentityManager(ctx context.Context, di database.Plugin, ii map[string]identity.Plugin, bi blockchain.Plugin, dm data.Manager) (Manager, error) { +func NewIdentityManager(ctx context.Context, di database.Plugin, ii identity.Plugin, bi blockchain.Plugin, dm data.Manager) (Manager, error) { if di == nil || ii == nil || bi == nil { return nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError, "IdentityManager") } diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index 8748c56acd..3390a0a8a5 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -46,6 +46,7 @@ var ( sharedstorageConfig = config.RootArray("plugins.sharedstorage") dataexchangeConfig = config.RootArray("plugins.dataexchange") identityConfig = config.RootArray("plugins.identity") + // Deprecated configs deprecatedTokensConfig = config.RootArray("tokens") deprecatedBlockchainConfig = config.RootSection("blockchain") @@ -55,15 +56,16 @@ var ( ) type Manager interface { - // Init initializes the manager Init(ctx context.Context, cancelCtx context.CancelFunc) error + Start() error + WaitStop() + + Orchestrator(ns string) orchestrator.Orchestrator + GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) } -//maybe add the orchestrator in this struct? -// mode?? type namespace struct { - // not sure if we need config - config config.Section + orchestrator orchestrator.Orchestrator multiparty bool database orchestrator.DatabasePlugin blockchain orchestrator.BlockchainPlugin @@ -76,7 +78,6 @@ type namespace struct { type namespaceManager struct { ctx context.Context cancelCtx context.CancelFunc - orchestrators map[string]orchestrator.Orchestrator pluginNames map[string]bool metrics metrics.Manager blockchains map[string]orchestrator.BlockchainPlugin @@ -85,7 +86,6 @@ type namespaceManager struct { sharedstorages map[string]orchestrator.SharedStoragePlugin dataexchanges map[string]orchestrator.DataexchangePlugin tokens map[string]orchestrator.TokensPlugin - database database.Plugin adminEvents adminevents.Manager namespaces map[string]namespace } @@ -124,28 +124,29 @@ func (nm *namespaceManager) Init(ctx context.Context, cancelCtx context.CancelFu } // Start an orchestrator per namespace - if err = nm.initOrchestrators(ctx, cancelCtx); err != nil { - return err - } - - return err -} - -func (nm *namespaceManager) initOrchestrators(ctx context.Context, cancelCtx context.CancelFunc) (err error) { for name, ns := range nm.namespaces { - //maybe export the namespace struct and have orchestrator take that as a parameter? - or := orchestrator.NewOrchestrator(ns.blockchain, ns.database, ns.sharedstorage, ns.dataexchange, ns.tokens, ns.identity, nm.metrics) + or := orchestrator.NewOrchestrator(name, ns.blockchain, ns.database, ns.sharedstorage, ns.dataexchange, ns.tokens, ns.identity, nm.metrics) if err = or.Init(ctx, cancelCtx); err != nil { return err } + ns.orchestrator = or + } + return nil +} - if err = or.Start(); err != nil { +func (nm *namespaceManager) Start() error { + for _, ns := range nm.namespaces { + if err := ns.orchestrator.Start(); err != nil { return err } - nm.orchestrators[name] = or } + return nil +} - return err +func (nm *namespaceManager) WaitStop() { + for _, ns := range nm.namespaces { + ns.orchestrator.WaitStop() + } } func (nm *namespaceManager) getPlugins(ctx context.Context) (err error) { @@ -658,3 +659,14 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name stri return nil } + +func (nm *namespaceManager) Orchestrator(ns string) orchestrator.Orchestrator { + if namespace, ok := nm.namespaces[ns]; ok { + return namespace.orchestrator + } + return nil +} + +func (nm *namespaceManager) GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) { + return nil, nil, nil +} diff --git a/internal/oapispec/apirequest.go b/internal/oapispec/apirequest.go index fcf737f268..6f9d8f0534 100644 --- a/internal/oapispec/apirequest.go +++ b/internal/oapispec/apirequest.go @@ -20,14 +20,14 @@ import ( "context" "net/http" - "github.com/hyperledger/firefly/internal/orchestrator" + "github.com/hyperledger/firefly/internal/namespace" "github.com/hyperledger/firefly/pkg/core" "github.com/hyperledger/firefly/pkg/database" ) type APIRequest struct { Ctx context.Context - Or orchestrator.Orchestrator + RootMgr namespace.Manager Req *http.Request QP map[string]string PP map[string]string diff --git a/internal/orchestrator/chart.go b/internal/orchestrator/chart.go index 2a2a86452e..9bde90bd5a 100644 --- a/internal/orchestrator/chart.go +++ b/internal/orchestrator/chart.go @@ -49,7 +49,7 @@ func (or *orchestrator) GetChartHistogram(ctx context.Context, ns string, startT intervals := or.getHistogramIntervals(startTime, endTime, buckets) - histogram, err := or.databases["database_0"].GetChartHistogram(ctx, ns, intervals, collection) + histogram, err := or.database.Plugin.GetChartHistogram(ctx, ns, intervals, collection) if err != nil { return nil, err } diff --git a/internal/orchestrator/data_query.go b/internal/orchestrator/data_query.go index 07cca924df..430ad0b931 100644 --- a/internal/orchestrator/data_query.go +++ b/internal/orchestrator/data_query.go @@ -50,7 +50,7 @@ func (or *orchestrator) verifyIDAndNamespace(ctx context.Context, ns, id string) } func (or *orchestrator) GetNamespace(ctx context.Context, ns string) (*core.Namespace, error) { - return or.databases["database_0"].GetNamespace(ctx, ns) + return or.database.Plugin.GetNamespace(ctx, ns) } func (or *orchestrator) GetTransactionByID(ctx context.Context, ns, id string) (*core.Transaction, error) { @@ -58,7 +58,7 @@ func (or *orchestrator) GetTransactionByID(ctx context.Context, ns, id string) ( if err != nil { return nil, err } - tx, err := or.databases["database_0"].GetTransactionByID(ctx, u) + tx, err := or.database.Plugin.GetTransactionByID(ctx, u) if err == nil && tx != nil { err = or.checkNamespace(ctx, ns, tx.Namespace) } @@ -75,7 +75,7 @@ func (or *orchestrator) GetTransactionOperations(ctx context.Context, ns, id str fb.Eq("tx", u), fb.Eq("namespace", ns), ) - return or.databases["database_0"].GetOperations(ctx, filter) + return or.database.Plugin.GetOperations(ctx, filter) } func (or *orchestrator) getMessageByID(ctx context.Context, ns, id string) (*core.Message, error) { @@ -83,7 +83,7 @@ func (or *orchestrator) getMessageByID(ctx context.Context, ns, id string) (*cor if err != nil { return nil, err } - msg, err := or.databases["database_0"].GetMessageByID(ctx, u) + msg, err := or.database.Plugin.GetMessageByID(ctx, u) if err == nil && msg == nil { return nil, i18n.NewError(ctx, coremsgs.Msg404NotFound) } @@ -126,7 +126,7 @@ func (or *orchestrator) GetBatchByID(ctx context.Context, ns, id string) (*core. if err != nil { return nil, err } - b, err := or.databases["database_0"].GetBatchByID(ctx, u) + b, err := or.database.Plugin.GetBatchByID(ctx, u) if err == nil && b != nil { err = or.checkNamespace(ctx, ns, b.Namespace) } @@ -138,7 +138,7 @@ func (or *orchestrator) GetDataByID(ctx context.Context, ns, id string) (*core.D if err != nil { return nil, err } - d, err := or.databases["database_0"].GetDataByID(ctx, u, true) + d, err := or.database.Plugin.GetDataByID(ctx, u, true) if err == nil && d != nil { err = or.checkNamespace(ctx, ns, d.Namespace) } @@ -150,7 +150,7 @@ func (or *orchestrator) GetDatatypeByID(ctx context.Context, ns, id string) (*co if err != nil { return nil, err } - dt, err := or.databases["database_0"].GetDatatypeByID(ctx, u) + dt, err := or.database.Plugin.GetDatatypeByID(ctx, u) if err == nil && dt != nil { err = or.checkNamespace(ctx, ns, dt.Namespace) } @@ -164,7 +164,7 @@ func (or *orchestrator) GetDatatypeByName(ctx context.Context, ns, name, version if err := core.ValidateFFNameFieldNoUUID(ctx, name, "name"); err != nil { return nil, err } - dt, err := or.databases["database_0"].GetDatatypeByName(ctx, ns, name, version) + dt, err := or.database.Plugin.GetDatatypeByName(ctx, ns, name, version) if err == nil && dt != nil { err = or.checkNamespace(ctx, ns, dt.Namespace) } @@ -176,7 +176,7 @@ func (or *orchestrator) GetOperationByIDNamespaced(ctx context.Context, ns, id s if err != nil { return nil, err } - o, err := or.databases["database_0"].GetOperationByID(ctx, u) + o, err := or.database.Plugin.GetOperationByID(ctx, u) if err == nil && o != nil { err = or.checkNamespace(ctx, ns, o.Namespace) } @@ -188,7 +188,7 @@ func (or *orchestrator) GetOperationByID(ctx context.Context, id string) (*core. if err != nil { return nil, err } - return or.databases["database_0"].GetOperationByID(ctx, u) + return or.database.Plugin.GetOperationByID(ctx, u) } func (or *orchestrator) GetEventByID(ctx context.Context, ns, id string) (*core.Event, error) { @@ -196,7 +196,7 @@ func (or *orchestrator) GetEventByID(ctx context.Context, ns, id string) (*core. if err != nil { return nil, err } - e, err := or.databases["database_0"].GetEventByID(ctx, u) + e, err := or.database.Plugin.GetEventByID(ctx, u) if err == nil && e != nil { err = or.checkNamespace(ctx, ns, e.Namespace) } @@ -204,7 +204,7 @@ func (or *orchestrator) GetEventByID(ctx context.Context, ns, id string) (*core. } func (or *orchestrator) GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) { - return or.databases["database_0"].GetNamespaces(ctx, filter) + return or.database.Plugin.GetNamespaces(ctx, filter) } func (or *orchestrator) scopeNS(ns string, filter database.AndFilter) database.AndFilter { @@ -213,17 +213,17 @@ func (or *orchestrator) scopeNS(ns string, filter database.AndFilter) database.A func (or *orchestrator) GetTransactions(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Transaction, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.databases["database_0"].GetTransactions(ctx, filter) + return or.database.Plugin.GetTransactions(ctx, filter) } func (or *orchestrator) GetMessages(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Message, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.databases["database_0"].GetMessages(ctx, filter) + return or.database.Plugin.GetMessages(ctx, filter) } func (or *orchestrator) GetMessagesWithData(ctx context.Context, ns string, filter database.AndFilter) ([]*core.MessageInOut, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - msgs, fr, err := or.databases["database_0"].GetMessages(ctx, filter) + msgs, fr, err := or.database.Plugin.GetMessages(ctx, filter) if err != nil { return nil, nil, err } @@ -255,7 +255,7 @@ func (or *orchestrator) getMessageTransactionID(ctx context.Context, ns, id stri if msg.BatchID == nil { return nil, i18n.NewError(ctx, coremsgs.MsgBatchNotSet) } - batch, err := or.databases["database_0"].GetBatchByID(ctx, msg.BatchID) + batch, err := or.database.Plugin.GetBatchByID(ctx, msg.BatchID) if err != nil { return nil, err } @@ -277,7 +277,7 @@ func (or *orchestrator) GetMessageTransaction(ctx context.Context, ns, id string if err != nil { return nil, err } - return or.databases["database_0"].GetTransactionByID(ctx, txID) + return or.database.Plugin.GetTransactionByID(ctx, txID) } func (or *orchestrator) GetMessageOperations(ctx context.Context, ns, id string) ([]*core.Operation, *database.FilterResult, error) { @@ -286,7 +286,7 @@ func (or *orchestrator) GetMessageOperations(ctx context.Context, ns, id string) return nil, nil, err } filter := database.OperationQueryFactory.NewFilter(ctx).Eq("tx", txID) - return or.databases["database_0"].GetOperations(ctx, filter) + return or.database.Plugin.GetOperations(ctx, filter) } func (or *orchestrator) GetMessageEvents(ctx context.Context, ns, id string, filter database.AndFilter) ([]*core.Event, *database.FilterResult, error) { @@ -303,17 +303,17 @@ func (or *orchestrator) GetMessageEvents(ctx context.Context, ns, id string, fil } filter = filter.Condition(filter.Builder().In("reference", referencedIDs)) // Execute the filter - return or.databases["database_0"].GetEvents(ctx, filter) + return or.database.Plugin.GetEvents(ctx, filter) } func (or *orchestrator) GetBatches(ctx context.Context, ns string, filter database.AndFilter) ([]*core.BatchPersisted, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.databases["database_0"].GetBatches(ctx, filter) + return or.database.Plugin.GetBatches(ctx, filter) } func (or *orchestrator) GetData(ctx context.Context, ns string, filter database.AndFilter) (core.DataArray, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.databases["database_0"].GetData(ctx, filter) + return or.database.Plugin.GetData(ctx, filter) } func (or *orchestrator) GetMessagesForData(ctx context.Context, ns, dataID string, filter database.AndFilter) ([]*core.Message, *database.FilterResult, error) { @@ -322,26 +322,26 @@ func (or *orchestrator) GetMessagesForData(ctx context.Context, ns, dataID strin if err != nil { return nil, nil, err } - return or.databases["database_0"].GetMessagesForData(ctx, u, filter) + return or.database.Plugin.GetMessagesForData(ctx, u, filter) } func (or *orchestrator) GetDatatypes(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Datatype, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.databases["database_0"].GetDatatypes(ctx, filter) + return or.database.Plugin.GetDatatypes(ctx, filter) } func (or *orchestrator) GetOperationsNamespaced(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Operation, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.databases["database_0"].GetOperations(ctx, filter) + return or.database.Plugin.GetOperations(ctx, filter) } func (or *orchestrator) GetOperations(ctx context.Context, filter database.AndFilter) ([]*core.Operation, *database.FilterResult, error) { - return or.databases["database_0"].GetOperations(ctx, filter) + return or.database.Plugin.GetOperations(ctx, filter) } func (or *orchestrator) GetEvents(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Event, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.databases["database_0"].GetEvents(ctx, filter) + return or.database.Plugin.GetEvents(ctx, filter) } func (or *orchestrator) GetBlockchainEventByID(ctx context.Context, ns, id string) (*core.BlockchainEvent, error) { @@ -349,7 +349,7 @@ func (or *orchestrator) GetBlockchainEventByID(ctx context.Context, ns, id strin if err != nil { return nil, err } - be, err := or.databases["database_0"].GetBlockchainEventByID(ctx, u) + be, err := or.database.Plugin.GetBlockchainEventByID(ctx, u) if err == nil && be != nil { err = or.checkNamespace(ctx, ns, be.Namespace) } @@ -357,7 +357,7 @@ func (or *orchestrator) GetBlockchainEventByID(ctx context.Context, ns, id strin } func (or *orchestrator) GetBlockchainEvents(ctx context.Context, ns string, filter database.AndFilter) ([]*core.BlockchainEvent, *database.FilterResult, error) { - return or.databases["database_0"].GetBlockchainEvents(ctx, or.scopeNS(ns, filter)) + return or.database.Plugin.GetBlockchainEvents(ctx, or.scopeNS(ns, filter)) } func (or *orchestrator) GetTransactionBlockchainEvents(ctx context.Context, ns, id string) ([]*core.BlockchainEvent, *database.FilterResult, error) { @@ -370,16 +370,16 @@ func (or *orchestrator) GetTransactionBlockchainEvents(ctx context.Context, ns, fb.Eq("tx.id", u), fb.Eq("namespace", ns), ) - return or.databases["database_0"].GetBlockchainEvents(ctx, filter) + return or.database.Plugin.GetBlockchainEvents(ctx, filter) } func (or *orchestrator) GetPins(ctx context.Context, filter database.AndFilter) ([]*core.Pin, *database.FilterResult, error) { - return or.databases["database_0"].GetPins(ctx, filter) + return or.database.Plugin.GetPins(ctx, filter) } func (or *orchestrator) GetEventsWithReferences(ctx context.Context, ns string, filter database.AndFilter) ([]*core.EnrichedEvent, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - events, fr, err := or.databases["database_0"].GetEvents(ctx, filter) + events, fr, err := or.database.Plugin.GetEvents(ctx, filter) if err != nil { return nil, nil, err } diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 2ab6c2f4d0..432a5925f7 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -158,6 +158,7 @@ type orchestrator struct { ctx context.Context cancelCtx context.CancelFunc started bool + namespace string blockchain BlockchainPlugin identity identity.Manager idPlugin IdentityPlugin @@ -185,8 +186,9 @@ type orchestrator struct { txHelper txcommon.Helper } -func NewOrchestrator(bc BlockchainPlugin, db DatabasePlugin, ss SharedStoragePlugin, dx DataexchangePlugin, tokens map[string]TokensPlugin, id IdentityPlugin, metrics metrics.Manager) Orchestrator { +func NewOrchestrator(ns string, bc BlockchainPlugin, db DatabasePlugin, ss SharedStoragePlugin, dx DataexchangePlugin, tokens map[string]TokensPlugin, id IdentityPlugin, metrics metrics.Manager) Orchestrator { or := &orchestrator{ + namespace: ns, blockchain: bc, database: db, sharedstorage: ss, @@ -216,27 +218,22 @@ func (or *orchestrator) Init(ctx context.Context, cancelCtx context.CancelFunc) } func (or *orchestrator) Start() (err error) { - // TODO: move bc start before batch + var ns *core.Namespace if err == nil { - err = or.batch.Start() + ns, err = or.database.Plugin.GetNamespace(or.ctx, or.namespace) } - var ns *core.Namespace if err == nil { - ns, err = or.database.Plugin.GetNamespace(or.ctx, core.SystemNamespace) - } - // if err == nil { - // for _, el := range or.blockchains { - // if err = el.ConfigureContract(or.ctx, &ns.Contracts); err != nil { - // break - // } - // if err = el.Start(); err != nil { - // break - // } - // } - // if err == nil { - // err = or.database.UpsertNamespace(or.ctx, ns, true) - // } - // } + err = or.blockchain.Plugin.ConfigureContract(or.ctx, &ns.Contracts) + } + if err == nil { + err = or.blockchain.Plugin.Start() + } + if err == nil { + err = or.database.Plugin.UpsertNamespace(or.ctx, ns, true) + } + if err == nil { + err = or.batch.Start() + } if err == nil { err = or.events.Start() } @@ -347,7 +344,7 @@ func (or *orchestrator) initPlugins(ctx context.Context) (err error) { return err } - err = or.blockchain.Plugin.Init(ctx, or.blockchain.Config, or, or.metrics) + err = or.blockchain.Plugin.Init(ctx, or.blockchain.Config, &or.bc, or.metrics) if err != nil { return err } @@ -396,7 +393,7 @@ func (or *orchestrator) initComponents(ctx context.Context) (err error) { } if or.identity == nil { - or.identity, err = identity.NewIdentityManager(ctx, or.database, or.identityPlugins, or.blockchain, or.data) + or.identity, err = identity.NewIdentityManager(ctx, or.database.Plugin, or.idPlugin.Plugin, or.blockchain.Plugin, or.data) if err != nil { return err } @@ -436,7 +433,7 @@ func (or *orchestrator) initComponents(ctx context.Context) (err error) { } if or.assets == nil { - or.assets, err = assets.NewAssetManager(ctx, or.database.Plugin, or.identity, or.data, or.syncasync, or.broadcast, or.messaging, or.tokens, or.metrics, or.operations, or.txHelper) + or.assets, err = assets.NewAssetManager(ctx, or.database.Plugin, or.identity, or.data, or.syncasync, or.broadcast, or.messaging, nil, or.metrics, or.operations, or.txHelper) if err != nil { return err } diff --git a/internal/orchestrator/status.go b/internal/orchestrator/status.go index f105286cc2..96aca7b4cb 100644 --- a/internal/orchestrator/status.go +++ b/internal/orchestrator/status.go @@ -34,49 +34,34 @@ func (or *orchestrator) getPlugins() core.NodeStatusPlugins { for name, plugin := range or.tokens { tokensArray = append(tokensArray, &core.NodeStatusPlugin{ Name: name, - PluginType: plugin.Name(), + PluginType: plugin.Plugin.Name(), }) } blockchainsArray := make([]*core.NodeStatusPlugin, 0) - for name, plugin := range or.blockchains { - blockchainsArray = append(blockchainsArray, &core.NodeStatusPlugin{ - Name: name, - PluginType: plugin.Name(), - }) - } + blockchainsArray = append(blockchainsArray, &core.NodeStatusPlugin{ + PluginType: or.blockchain.Plugin.Name(), + }) databasesArray := make([]*core.NodeStatusPlugin, 0) - for name, plugin := range or.databases { - databasesArray = append(databasesArray, &core.NodeStatusPlugin{ - Name: name, - PluginType: plugin.Name(), - }) - } + databasesArray = append(databasesArray, &core.NodeStatusPlugin{ + PluginType: or.database.Plugin.Name(), + }) sharedstorageArray := make([]*core.NodeStatusPlugin, 0) - for name, plugin := range or.sharedstoragePlugins { - sharedstorageArray = append(sharedstorageArray, &core.NodeStatusPlugin{ - Name: name, - PluginType: plugin.Name(), - }) - } + sharedstorageArray = append(sharedstorageArray, &core.NodeStatusPlugin{ + PluginType: or.sharedstorage.Plugin.Name(), + }) dataexchangeArray := make([]*core.NodeStatusPlugin, 0) - for name, plugin := range or.dataexchangePlugins { - dataexchangeArray = append(dataexchangeArray, &core.NodeStatusPlugin{ - Name: name, - PluginType: plugin.Name(), - }) - } + dataexchangeArray = append(dataexchangeArray, &core.NodeStatusPlugin{ + PluginType: or.dataexchange.Plugin.Name(), + }) identityPluginArray := make([]*core.NodeStatusPlugin, 0) - for name, plugin := range or.identityPlugins { - identityPluginArray = append(identityPluginArray, &core.NodeStatusPlugin{ - Name: name, - PluginType: plugin.Name(), - }) - } + identityPluginArray = append(identityPluginArray, &core.NodeStatusPlugin{ + PluginType: or.idPlugin.Plugin.Name(), + }) return core.NodeStatusPlugins{ Blockchain: blockchainsArray, diff --git a/internal/orchestrator/subscriptions.go b/internal/orchestrator/subscriptions.go index 901f3500fc..4400538b1f 100644 --- a/internal/orchestrator/subscriptions.go +++ b/internal/orchestrator/subscriptions.go @@ -58,7 +58,7 @@ func (or *orchestrator) DeleteSubscription(ctx context.Context, ns, id string) e if err != nil { return err } - sub, err := or.databases["database_0"].GetSubscriptionByID(ctx, u) + sub, err := or.database.Plugin.GetSubscriptionByID(ctx, u) if err != nil { return err } @@ -70,7 +70,7 @@ func (or *orchestrator) DeleteSubscription(ctx context.Context, ns, id string) e func (or *orchestrator) GetSubscriptions(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Subscription, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.databases["database_0"].GetSubscriptions(ctx, filter) + return or.database.Plugin.GetSubscriptions(ctx, filter) } func (or *orchestrator) GetSubscriptionByID(ctx context.Context, ns, id string) (*core.Subscription, error) { @@ -78,5 +78,5 @@ func (or *orchestrator) GetSubscriptionByID(ctx context.Context, ns, id string) if err != nil { return nil, err } - return or.databases["database_0"].GetSubscriptionByID(ctx, u) + return or.database.Plugin.GetSubscriptionByID(ctx, u) } diff --git a/internal/orchestrator/txn_status.go b/internal/orchestrator/txn_status.go index 6555a85ee5..554163a4d2 100644 --- a/internal/orchestrator/txn_status.go +++ b/internal/orchestrator/txn_status.go @@ -101,7 +101,7 @@ func (or *orchestrator) GetTransactionStatus(ctx context.Context, ns, id string) updateStatus(result, core.OpStatusPending) } f := database.BatchQueryFactory.NewFilter(ctx) - switch batches, _, err := or.databases["database_0"].GetBatches(ctx, f.Eq("tx.id", id)); { + switch batches, _, err := or.database.Plugin.GetBatches(ctx, f.Eq("tx.id", id)); { case err != nil: return nil, err case len(batches) == 0: @@ -120,7 +120,7 @@ func (or *orchestrator) GetTransactionStatus(ctx context.Context, ns, id string) case core.TransactionTypeTokenPool: // Note: no assumptions about blockchain events here (may or may not contain one) f := database.TokenPoolQueryFactory.NewFilter(ctx) - switch pools, _, err := or.databases["database_0"].GetTokenPools(ctx, f.Eq("tx.id", id)); { + switch pools, _, err := or.database.Plugin.GetTokenPools(ctx, f.Eq("tx.id", id)); { case err != nil: return nil, err case len(pools) == 0: @@ -150,7 +150,7 @@ func (or *orchestrator) GetTransactionStatus(ctx context.Context, ns, id string) updateStatus(result, core.OpStatusPending) } f := database.TokenTransferQueryFactory.NewFilter(ctx) - switch transfers, _, err := or.databases["database_0"].GetTokenTransfers(ctx, f.Eq("tx.id", id)); { + switch transfers, _, err := or.database.Plugin.GetTokenTransfers(ctx, f.Eq("tx.id", id)); { case err != nil: return nil, err case len(transfers) == 0: @@ -172,7 +172,7 @@ func (or *orchestrator) GetTransactionStatus(ctx context.Context, ns, id string) updateStatus(result, core.OpStatusPending) } f := database.TokenApprovalQueryFactory.NewFilter(ctx) - switch approvals, _, err := or.databases["database_0"].GetTokenApprovals(ctx, f.Eq("tx.id", id)); { + switch approvals, _, err := or.database.Plugin.GetTokenApprovals(ctx, f.Eq("tx.id", id)); { case err != nil: return nil, err case len(approvals) == 0: diff --git a/mocks/apiservermocks/server.go b/mocks/apiservermocks/server.go index fd2fcc3815..095533c2f5 100644 --- a/mocks/apiservermocks/server.go +++ b/mocks/apiservermocks/server.go @@ -5,7 +5,7 @@ package apiservermocks import ( context "context" - orchestrator "github.com/hyperledger/firefly/internal/orchestrator" + namespace "github.com/hyperledger/firefly/internal/namespace" mock "github.com/stretchr/testify/mock" ) @@ -14,13 +14,13 @@ type Server struct { mock.Mock } -// Serve provides a mock function with given fields: ctx, o -func (_m *Server) Serve(ctx context.Context, o orchestrator.Orchestrator) error { - ret := _m.Called(ctx, o) +// Serve provides a mock function with given fields: ctx, mgr +func (_m *Server) Serve(ctx context.Context, mgr namespace.Manager) error { + ret := _m.Called(ctx, mgr) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, orchestrator.Orchestrator) error); ok { - r0 = rf(ctx, o) + if rf, ok := ret.Get(0).(func(context.Context, namespace.Manager) error); ok { + r0 = rf(ctx, mgr) } else { r0 = ret.Error(0) } diff --git a/mocks/namespacemocks/manager.go b/mocks/namespacemocks/manager.go index cec55ed531..efe83c99eb 100644 --- a/mocks/namespacemocks/manager.go +++ b/mocks/namespacemocks/manager.go @@ -5,8 +5,12 @@ package namespacemocks import ( context "context" + core "github.com/hyperledger/firefly/pkg/core" database "github.com/hyperledger/firefly/pkg/database" + mock "github.com/stretchr/testify/mock" + + orchestrator "github.com/hyperledger/firefly/internal/orchestrator" ) // Manager is an autogenerated mock type for the Manager type @@ -14,16 +18,83 @@ type Manager struct { mock.Mock } -// Init provides a mock function with given fields: ctx, di -func (_m *Manager) Init(ctx context.Context, di database.Plugin) error { - ret := _m.Called(ctx, di) +// GetNamespaces provides a mock function with given fields: ctx, filter +func (_m *Manager) GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) { + ret := _m.Called(ctx, filter) + + var r0 []*core.Namespace + if rf, ok := ret.Get(0).(func(context.Context, database.AndFilter) []*core.Namespace); ok { + r0 = rf(ctx, filter) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*core.Namespace) + } + } + + var r1 *database.FilterResult + if rf, ok := ret.Get(1).(func(context.Context, database.AndFilter) *database.FilterResult); ok { + r1 = rf(ctx, 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, database.AndFilter) error); ok { + r2 = rf(ctx, filter) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// Init provides a mock function with given fields: ctx, cancelCtx +func (_m *Manager) Init(ctx context.Context, cancelCtx context.CancelFunc) error { + ret := _m.Called(ctx, cancelCtx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, context.CancelFunc) error); ok { + r0 = rf(ctx, cancelCtx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Orchestrator provides a mock function with given fields: ns +func (_m *Manager) Orchestrator(ns string) orchestrator.Orchestrator { + ret := _m.Called(ns) + + var r0 orchestrator.Orchestrator + if rf, ok := ret.Get(0).(func(string) orchestrator.Orchestrator); ok { + r0 = rf(ns) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(orchestrator.Orchestrator) + } + } + + return r0 +} + +// Start provides a mock function with given fields: +func (_m *Manager) Start() error { + ret := _m.Called() var r0 error - if rf, ok := ret.Get(0).(func(context.Context, database.Plugin) error); ok { - r0 = rf(ctx, di) + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() } else { r0 = ret.Error(0) } return r0 } + +// WaitStop provides a mock function with given fields: +func (_m *Manager) WaitStop() { + _m.Called() +} From 494e89762f5c4eee5f0ab594b24c61a4c3461083 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 3 Jun 2022 12:09:30 -0400 Subject: [PATCH 03/33] Remove global routes Some of these may come back in a different form, but they need to be removed for the moment because they exist outside of the namespaced orchestrators. Signed-off-by: Andrew Richardson --- internal/apiserver/admin_routes.go | 6 +-- .../apiserver/route_admin_get_op_by_id.go | 44 ------------------- .../route_admin_get_op_by_id_test.go | 39 ---------------- internal/apiserver/route_admin_get_ops.go | 41 ----------------- .../apiserver/route_admin_get_ops_test.go | 39 ---------------- .../apiserver/route_admin_put_op_by_id.go | 44 ------------------- .../route_admin_put_op_by_id_test.go | 42 ------------------ .../route_get_status_batchmanager.go | 42 ------------------ .../route_get_status_batchmanager_test.go | 42 ------------------ internal/apiserver/route_get_status_pins.go | 42 ------------------ .../apiserver/route_get_status_pins_test.go | 39 ---------------- .../apiserver/route_get_status_websockets.go | 41 ----------------- .../route_get_status_websockets_test.go | 40 ----------------- internal/apiserver/routes.go | 3 -- 14 files changed, 1 insertion(+), 503 deletions(-) delete mode 100644 internal/apiserver/route_admin_get_op_by_id.go delete mode 100644 internal/apiserver/route_admin_get_op_by_id_test.go delete mode 100644 internal/apiserver/route_admin_get_ops.go delete mode 100644 internal/apiserver/route_admin_get_ops_test.go delete mode 100644 internal/apiserver/route_admin_put_op_by_id.go delete mode 100644 internal/apiserver/route_admin_put_op_by_id_test.go delete mode 100644 internal/apiserver/route_get_status_batchmanager.go delete mode 100644 internal/apiserver/route_get_status_batchmanager_test.go delete mode 100644 internal/apiserver/route_get_status_pins.go delete mode 100644 internal/apiserver/route_get_status_pins_test.go delete mode 100644 internal/apiserver/route_get_status_websockets.go delete mode 100644 internal/apiserver/route_get_status_websockets_test.go diff --git a/internal/apiserver/admin_routes.go b/internal/apiserver/admin_routes.go index 1f8bbca52b..388666b1b0 100644 --- a/internal/apiserver/admin_routes.go +++ b/internal/apiserver/admin_routes.go @@ -18,8 +18,4 @@ package apiserver import "github.com/hyperledger/firefly/internal/oapispec" -var adminRoutes = []*oapispec.Route{ - adminGetOpByID, - adminGetOps, - adminPatchOpByID, -} +var adminRoutes = []*oapispec.Route{} diff --git a/internal/apiserver/route_admin_get_op_by_id.go b/internal/apiserver/route_admin_get_op_by_id.go deleted file mode 100644 index ba3f8e9f86..0000000000 --- a/internal/apiserver/route_admin_get_op_by_id.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright © 2022 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/coremsgs" - "github.com/hyperledger/firefly/internal/oapispec" - "github.com/hyperledger/firefly/pkg/core" -) - -var adminGetOpByID = &oapispec.Route{ - Name: "adminGetOpByID", - Path: "operations/{opid}", - Method: http.MethodGet, - PathParams: []*oapispec.PathParam{ - {Name: "opid", Description: coremsgs.APIParamsOperationIDGet}, - }, - QueryParams: nil, - FilterFactory: nil, - Description: coremsgs.APIEndpointsAdminGetOpByID, - JSONInputValue: nil, - JSONOutputValue: func() interface{} { return &core.Operation{} }, - JSONOutputCodes: []int{http.StatusOK}, - JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).GetOperationByID(r.Ctx, r.PP["opid"]) - return output, err - }, -} diff --git a/internal/apiserver/route_admin_get_op_by_id_test.go b/internal/apiserver/route_admin_get_op_by_id_test.go deleted file mode 100644 index b6dd2f3d18..0000000000 --- a/internal/apiserver/route_admin_get_op_by_id_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// 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/pkg/core" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestAdminGetOperationByID(t *testing.T) { - o, r := newTestAdminServer() - req := httptest.NewRequest("GET", "/admin/api/v1/operations/abcd12345", nil) - req.Header.Set("Content-Type", "application/json; charset=utf-8") - res := httptest.NewRecorder() - - o.On("GetOperationByID", mock.Anything, "abcd12345"). - Return(&core.Operation{}, nil) - r.ServeHTTP(res, req) - - assert.Equal(t, 200, res.Result().StatusCode) -} diff --git a/internal/apiserver/route_admin_get_ops.go b/internal/apiserver/route_admin_get_ops.go deleted file mode 100644 index 75738f4e8d..0000000000 --- a/internal/apiserver/route_admin_get_ops.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright © 2022 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/coremsgs" - "github.com/hyperledger/firefly/internal/oapispec" - "github.com/hyperledger/firefly/pkg/core" - "github.com/hyperledger/firefly/pkg/database" -) - -var adminGetOps = &oapispec.Route{ - Name: "adminGetOps", - Path: "operations", - Method: http.MethodGet, - QueryParams: nil, - FilterFactory: database.OperationQueryFactory, - Description: coremsgs.APIEndpointsAdminGetOps, - JSONInputValue: nil, - JSONOutputValue: func() interface{} { return []*core.Operation{} }, - JSONOutputCodes: []int{http.StatusOK}, - JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetOperations(r.Ctx, r.Filter)) - }, -} diff --git a/internal/apiserver/route_admin_get_ops_test.go b/internal/apiserver/route_admin_get_ops_test.go deleted file mode 100644 index 45f5f03fe6..0000000000 --- a/internal/apiserver/route_admin_get_ops_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// 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/pkg/core" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestAdminGetOperations(t *testing.T) { - o, r := newTestAdminServer() - req := httptest.NewRequest("GET", "/admin/api/v1/operations", nil) - req.Header.Set("Content-Type", "application/json; charset=utf-8") - res := httptest.NewRecorder() - - o.On("GetOperations", mock.Anything, mock.Anything). - Return([]*core.Operation{}, nil, nil) - r.ServeHTTP(res, req) - - assert.Equal(t, 200, res.Result().StatusCode) -} diff --git a/internal/apiserver/route_admin_put_op_by_id.go b/internal/apiserver/route_admin_put_op_by_id.go deleted file mode 100644 index 0e48654356..0000000000 --- a/internal/apiserver/route_admin_put_op_by_id.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright © 2022 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/coremsgs" - "github.com/hyperledger/firefly/internal/oapispec" - "github.com/hyperledger/firefly/pkg/core" -) - -var adminPatchOpByID = &oapispec.Route{ - Name: "adminPatchOpByID", - Path: "operations/{opid}", - Method: http.MethodPut, - PathParams: []*oapispec.PathParam{ - {Name: "opid", Description: coremsgs.APIParamsConfigRecordKeyUpdate}, - }, - QueryParams: nil, - FilterFactory: nil, - Description: coremsgs.APIEndpointsAdminPatchOpByID, - JSONInputValue: func() interface{} { return &core.Operation{} }, - JSONOutputValue: func() interface{} { return &core.Operation{} }, - JSONOutputCodes: []int{http.StatusOK}, - JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output, err = getOr(r.Ctx).Operations().ResolveOperationByID(r.Ctx, r.PP["opid"], r.Input.(*core.Operation)) - return output, err - }, -} diff --git a/internal/apiserver/route_admin_put_op_by_id_test.go b/internal/apiserver/route_admin_put_op_by_id_test.go deleted file mode 100644 index f54d699ac6..0000000000 --- a/internal/apiserver/route_admin_put_op_by_id_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// 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 ( - "bytes" - "net/http/httptest" - "testing" - - "github.com/hyperledger/firefly/mocks/operationmocks" - "github.com/hyperledger/firefly/pkg/core" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestAdminPatchOperationByID(t *testing.T) { - o, r := newTestAdminServer() - req := httptest.NewRequest("PUT", "/admin/api/v1/operations/abcd12345", bytes.NewReader([]byte("{}"))) - req.Header.Set("Content-Type", "application/json; charset=utf-8") - res := httptest.NewRecorder() - - mop := &operationmocks.Manager{} - o.On("Operations").Return(mop) - mop.On("ResolveOperationByID", mock.Anything, "abcd12345", mock.AnythingOfType("*core.Operation")).Return(&core.Operation{}, nil) - r.ServeHTTP(res, req) - - assert.Equal(t, 200, res.Result().StatusCode) -} diff --git a/internal/apiserver/route_get_status_batchmanager.go b/internal/apiserver/route_get_status_batchmanager.go deleted file mode 100644 index 5abcc49deb..0000000000 --- a/internal/apiserver/route_get_status_batchmanager.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright © 2022 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/batch" - "github.com/hyperledger/firefly/internal/coremsgs" - "github.com/hyperledger/firefly/internal/oapispec" -) - -var getStatusBatchManager = &oapispec.Route{ - Name: "getStatusBatchManager", - Path: "status/batchmanager", - Method: http.MethodGet, - PathParams: nil, - QueryParams: nil, - FilterFactory: nil, - Description: coremsgs.APIEndpointsGetStatusBatchManager, - JSONInputValue: nil, - JSONOutputValue: func() interface{} { return &batch.ManagerStatus{} }, - JSONOutputCodes: []int{http.StatusOK}, - JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - output = getOr(r.Ctx).BatchManager().Status() - return output, nil - }, -} diff --git a/internal/apiserver/route_get_status_batchmanager_test.go b/internal/apiserver/route_get_status_batchmanager_test.go deleted file mode 100644 index 07380af68c..0000000000 --- a/internal/apiserver/route_get_status_batchmanager_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// 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/internal/batch" - "github.com/hyperledger/firefly/mocks/batchmocks" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestGetStatusBatching(t *testing.T) { - o, r := newTestAPIServer() - req := httptest.NewRequest("GET", "/api/v1/status/batchmanager", nil) - req.Header.Set("Content-Type", "application/json; charset=utf-8") - res := httptest.NewRecorder() - - mbm := &batchmocks.Manager{} - o.On("BatchManager").Return(mbm) - mbm.On("Status", mock.Anything, mock.Anything). - Return(&batch.ManagerStatus{}, nil) - r.ServeHTTP(res, req) - - assert.Equal(t, 200, res.Result().StatusCode) -} diff --git a/internal/apiserver/route_get_status_pins.go b/internal/apiserver/route_get_status_pins.go deleted file mode 100644 index b3b6fd7d97..0000000000 --- a/internal/apiserver/route_get_status_pins.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright © 2022 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/coremsgs" - "github.com/hyperledger/firefly/internal/oapispec" - "github.com/hyperledger/firefly/pkg/core" - "github.com/hyperledger/firefly/pkg/database" -) - -var getStatusPins = &oapispec.Route{ - Name: "getStatusPins", - Path: "status/pins", - Method: http.MethodGet, - PathParams: nil, - QueryParams: nil, - FilterFactory: database.PinQueryFactory, - Description: coremsgs.APIEndpointsGetStatusPins, - JSONInputValue: nil, - JSONOutputValue: func() interface{} { return []core.Pin{} }, - JSONOutputCodes: []int{http.StatusOK}, - JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return filterResult(getOr(r.Ctx).GetPins(r.Ctx, r.Filter)) - }, -} diff --git a/internal/apiserver/route_get_status_pins_test.go b/internal/apiserver/route_get_status_pins_test.go deleted file mode 100644 index 4ea3d4e19e..0000000000 --- a/internal/apiserver/route_get_status_pins_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// 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/pkg/core" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -func TestGetStatusPins(t *testing.T) { - o, r := newTestAPIServer() - req := httptest.NewRequest("GET", "/api/v1/status/pins", nil) - req.Header.Set("Content-Type", "application/json; charset=utf-8") - res := httptest.NewRecorder() - - o.On("GetPins", mock.Anything, mock.Anything). - Return([]*core.Pin{}, nil, nil) - r.ServeHTTP(res, req) - - assert.Equal(t, 200, res.Result().StatusCode) -} diff --git a/internal/apiserver/route_get_status_websockets.go b/internal/apiserver/route_get_status_websockets.go deleted file mode 100644 index 9117038d5c..0000000000 --- a/internal/apiserver/route_get_status_websockets.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright © 2022 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/coremsgs" - "github.com/hyperledger/firefly/internal/oapispec" - "github.com/hyperledger/firefly/pkg/core" -) - -var getStatusWebSockets = &oapispec.Route{ - Name: "getStatusWebSockets", - Path: "status/websockets", - Method: http.MethodGet, - PathParams: nil, - QueryParams: nil, - FilterFactory: nil, - Description: coremsgs.APIEndpointsGetStatusWebSockets, - JSONInputValue: nil, - JSONOutputValue: func() interface{} { return &core.WebSocketStatus{} }, - JSONOutputCodes: []int{http.StatusOK}, - JSONHandler: func(r *oapispec.APIRequest) (output interface{}, err error) { - return getOr(r.Ctx).Events().GetWebSocketStatus(), nil - }, -} diff --git a/internal/apiserver/route_get_status_websockets_test.go b/internal/apiserver/route_get_status_websockets_test.go deleted file mode 100644 index 2952de4175..0000000000 --- a/internal/apiserver/route_get_status_websockets_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// 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/eventmocks" - "github.com/hyperledger/firefly/pkg/core" - "github.com/stretchr/testify/assert" -) - -func TestGetStatusWebSockets(t *testing.T) { - o, r := newTestAPIServer() - mem := &eventmocks.EventManager{} - o.On("Events").Return(mem) - req := httptest.NewRequest("GET", "/api/v1/status/websockets", nil) - req.Header.Set("Content-Type", "application/json; charset=utf-8") - res := httptest.NewRecorder() - - mem.On("GetWebSocketStatus").Return(&core.WebSocketStatus{}) - r.ServeHTTP(res, req) - - assert.Equal(t, 200, res.Result().StatusCode) -} diff --git a/internal/apiserver/routes.go b/internal/apiserver/routes.go index 17cad4293d..1298271bbf 100644 --- a/internal/apiserver/routes.go +++ b/internal/apiserver/routes.go @@ -35,9 +35,6 @@ var routes = append( getNetworkOrg, getNetworkOrgs, getStatus, - getStatusBatchManager, - getStatusPins, - getStatusWebSockets, postNetworkAction, postNewOrganization, postNewOrganizationSelf, From fceb2eeae35af60cdc4ef5cdf94c788da599fead Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 3 Jun 2022 12:29:24 -0400 Subject: [PATCH 04/33] Fix up orchestrator tests Temporarily disable many of the tests that are no longer relevant. Signed-off-by: Andrew Richardson --- internal/orchestrator/chart_test.go | 2 - internal/orchestrator/data_query_test.go | 62 --------------------- internal/orchestrator/orchestrator_test.go | 53 +++++++----------- internal/orchestrator/status_test.go | 5 -- internal/orchestrator/subscriptions_test.go | 6 -- internal/orchestrator/txn_status_test.go | 21 ------- 6 files changed, 20 insertions(+), 129 deletions(-) diff --git a/internal/orchestrator/chart_test.go b/internal/orchestrator/chart_test.go index 7a48326cd0..0dac78071d 100644 --- a/internal/orchestrator/chart_test.go +++ b/internal/orchestrator/chart_test.go @@ -58,7 +58,6 @@ func TestGetHistogramBadStartEndTimes(t *testing.T) { func TestGetHistogramFailDB(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi intervals := makeTestIntervals(1000000000, 10) or.mdi.On("GetChartHistogram", mock.Anything, "ns1", intervals, database.CollectionName("test")).Return(nil, fmt.Errorf("pop")) _, err := or.GetChartHistogram(context.Background(), "ns1", 1000000000, 1000000010, 10, database.CollectionName("test")) @@ -67,7 +66,6 @@ func TestGetHistogramFailDB(t *testing.T) { func TestGetHistogramSuccess(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi intervals := makeTestIntervals(1000000000, 10) mockHistogram := []*core.ChartHistogram{} diff --git a/internal/orchestrator/data_query_test.go b/internal/orchestrator/data_query_test.go index 5602e64170..7b69e9dfe4 100644 --- a/internal/orchestrator/data_query_test.go +++ b/internal/orchestrator/data_query_test.go @@ -30,7 +30,6 @@ import ( func TestGetNamespace(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi or.mdi.On("GetNamespace", mock.Anything, "ns1").Return(nil, nil) _, err := or.GetNamespace(context.Background(), "ns1") assert.NoError(t, err) @@ -38,7 +37,6 @@ func TestGetNamespace(t *testing.T) { func TestGetTransactionByID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetTransactionByID", mock.Anything, u).Return(nil, nil) _, err := or.GetTransactionByID(context.Background(), "ns1", u.String()) @@ -47,14 +45,12 @@ func TestGetTransactionByID(t *testing.T) { func TestGetTransactionByIDBadID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, err := or.GetTransactionByID(context.Background(), "", "") assert.Regexp(t, "FF00138", err) } func TestGetTransactionOperationsOk(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi or.mdi.On("GetOperations", mock.Anything, mock.Anything).Return([]*core.Operation{}, nil, nil) _, _, err := or.GetTransactionOperations(context.Background(), "ns1", fftypes.NewUUID().String()) assert.NoError(t, err) @@ -62,14 +58,12 @@ func TestGetTransactionOperationsOk(t *testing.T) { func TestGetTransactionOperationBadID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, _, err := or.GetTransactionOperations(context.Background(), "ns1", "") assert.Regexp(t, "FF00138", err) } func TestGetNamespaces(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi or.mdi.On("GetNamespaces", mock.Anything, mock.Anything).Return([]*core.Namespace{}, nil, nil) fb := database.NamespaceQueryFactory.NewFilter(context.Background()) f := fb.And(fb.Eq("name", "ns1")) @@ -79,7 +73,6 @@ func TestGetNamespaces(t *testing.T) { func TestGetTransactions(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetTransactions", mock.Anything, mock.Anything).Return([]*core.Transaction{}, nil, nil) fb := database.TransactionQueryFactory.NewFilter(context.Background()) @@ -90,14 +83,12 @@ func TestGetTransactions(t *testing.T) { func TestGetMessageByIDBadID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, err := or.GetMessageByID(context.Background(), "", "") assert.Regexp(t, "FF00138", err) } func TestGetMessageByIDWrongNSReturned(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() or.mdi.On("GetMessageByID", mock.Anything, mock.Anything).Return(&core.Message{ Header: core.MessageHeader{ @@ -110,7 +101,6 @@ func TestGetMessageByIDWrongNSReturned(t *testing.T) { func TestGetMessageByIDNoValuesOk(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() msg := &core.Message{ Header: core.MessageHeader{ @@ -135,7 +125,6 @@ func TestGetMessageByIDNoValuesOk(t *testing.T) { func TestGetMessageByIDWithDataOk(t *testing.T) { or := newTestOrchestrator() msgID := fftypes.NewUUID() - or.databases["database_0"] = or.mdi msg := &core.Message{ Header: core.MessageHeader{ Namespace: "ns1", @@ -164,7 +153,6 @@ func TestGetMessageByIDWithDataOk(t *testing.T) { func TestGetMessageByIDWithDataMsgFail(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() or.mdi.On("GetMessageByID", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("pop")) @@ -174,7 +162,6 @@ func TestGetMessageByIDWithDataMsgFail(t *testing.T) { func TestGetMessageByIDWithDataFail(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() msg := &core.Message{ Header: core.MessageHeader{ @@ -195,7 +182,6 @@ func TestGetMessageByIDWithDataFail(t *testing.T) { func TestGetMessages(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetMessages", mock.Anything, mock.Anything).Return([]*core.Message{}, nil, nil) fb := database.MessageQueryFactory.NewFilter(context.Background()) @@ -206,7 +192,6 @@ func TestGetMessages(t *testing.T) { func TestGetMessagesWithDataFailMsg(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi or.mdi.On("GetMessages", mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("pop")) fb := database.MessageQueryFactory.NewFilter(context.Background()) f := fb.And(fb.Eq("id", fftypes.NewUUID())) @@ -216,7 +201,6 @@ func TestGetMessagesWithDataFailMsg(t *testing.T) { func TestGetMessagesWithDataOk(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() msgID := fftypes.NewUUID() msg := &core.Message{ @@ -235,7 +219,6 @@ func TestGetMessagesWithDataOk(t *testing.T) { func TestGetMessagesWithDataFail(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() msgID := fftypes.NewUUID() msg := &core.Message{ @@ -254,7 +237,6 @@ func TestGetMessagesWithDataFail(t *testing.T) { func TestGetMessagesForData(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetMessagesForData", mock.Anything, u, mock.Anything).Return([]*core.Message{}, nil, nil) fb := database.MessageQueryFactory.NewFilter(context.Background()) @@ -265,7 +247,6 @@ func TestGetMessagesForData(t *testing.T) { func TestGetMessagesForDataBadID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi f := database.MessageQueryFactory.NewFilter(context.Background()).And() _, _, err := or.GetMessagesForData(context.Background(), "!wrong", "!bad", f) assert.Regexp(t, "FF00138", err) @@ -273,7 +254,6 @@ func TestGetMessagesForDataBadID(t *testing.T) { func TestGetMessageTransactionOk(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() batchID := fftypes.NewUUID() txID := fftypes.NewUUID() @@ -301,7 +281,6 @@ func TestGetMessageTransactionOk(t *testing.T) { func TestGetMessageTransactionOperations(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() batchID := fftypes.NewUUID() txID := fftypes.NewUUID() @@ -327,7 +306,6 @@ func TestGetMessageTransactionOperations(t *testing.T) { func TestGetMessageTransactionOperationsNoTX(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() or.mdi.On("GetMessageByID", mock.Anything, msgID).Return(&core.Message{ Header: core.MessageHeader{ @@ -341,7 +319,6 @@ func TestGetMessageTransactionOperationsNoTX(t *testing.T) { func TestGetMessageTransactionNoBatchTX(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() batchID := fftypes.NewUUID() or.mdi.On("GetMessageByID", mock.Anything, msgID).Return(&core.Message{ @@ -358,7 +335,6 @@ func TestGetMessageTransactionNoBatchTX(t *testing.T) { func TestGetMessageTransactionNoBatch(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() batchID := fftypes.NewUUID() or.mdi.On("GetMessageByID", mock.Anything, msgID).Return(&core.Message{ @@ -375,7 +351,6 @@ func TestGetMessageTransactionNoBatch(t *testing.T) { func TestGetMessageTransactionBatchLookupErr(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() batchID := fftypes.NewUUID() or.mdi.On("GetMessageByID", mock.Anything, msgID).Return(&core.Message{ @@ -392,7 +367,6 @@ func TestGetMessageTransactionBatchLookupErr(t *testing.T) { func TestGetMessageTransactionNoBatchID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() or.mdi.On("GetMessageByID", mock.Anything, msgID).Return(&core.Message{ Header: core.MessageHeader{ @@ -406,7 +380,6 @@ func TestGetMessageTransactionNoBatchID(t *testing.T) { func TestGetMessageTransactionNoTx(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() or.mdi.On("GetMessageByID", mock.Anything, msgID).Return(&core.Message{ Header: core.MessageHeader{ @@ -419,7 +392,6 @@ func TestGetMessageTransactionNoTx(t *testing.T) { func TestGetMessageTransactionMessageNotFound(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msgID := fftypes.NewUUID() or.mdi.On("GetMessageByID", mock.Anything, msgID).Return(nil, nil) _, err := or.GetMessageTransaction(context.Background(), "ns1", msgID.String()) @@ -428,7 +400,6 @@ func TestGetMessageTransactionMessageNotFound(t *testing.T) { func TestGetMessageData(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msg := &core.Message{ Header: core.MessageHeader{ Namespace: "ns1", @@ -447,7 +418,6 @@ func TestGetMessageData(t *testing.T) { func TestGetMessageDataBadMsg(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi or.mdi.On("GetMessageByID", mock.Anything, mock.Anything).Return(nil, nil) _, err := or.GetMessageData(context.Background(), "ns1", fftypes.NewUUID().String()) assert.Regexp(t, "FF10109", err) @@ -455,7 +425,6 @@ func TestGetMessageDataBadMsg(t *testing.T) { func TestGetMessageEventsOk(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi msg := &core.Message{ Header: core.MessageHeader{ Namespace: "ns1", @@ -483,7 +452,6 @@ func TestGetMessageEventsOk(t *testing.T) { func TestGetMessageEventsBadMsgID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi fb := database.EventQueryFactory.NewFilter(context.Background()) f := fb.And(fb.Eq("type", core.EventTypeMessageConfirmed)) or.mdi.On("GetMessageByID", mock.Anything, mock.Anything).Return(nil, nil) @@ -494,7 +462,6 @@ func TestGetMessageEventsBadMsgID(t *testing.T) { func TestGetBatchByID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetBatchByID", mock.Anything, u).Return(&core.BatchPersisted{ BatchHeader: core.BatchHeader{ @@ -507,14 +474,12 @@ func TestGetBatchByID(t *testing.T) { func TestGetBatchByIDBadID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, err := or.GetBatchByID(context.Background(), "", "") assert.Regexp(t, "FF00138", err) } func TestGetBatches(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetBatches", mock.Anything, mock.Anything).Return([]*core.BatchPersisted{}, nil, nil) fb := database.BatchQueryFactory.NewFilter(context.Background()) @@ -525,7 +490,6 @@ func TestGetBatches(t *testing.T) { func TestGetDataByID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetDataByID", mock.Anything, u, true).Return(&core.Data{ Namespace: "ns1", @@ -536,14 +500,12 @@ func TestGetDataByID(t *testing.T) { func TestGetDataByIDBadID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, err := or.GetDataByID(context.Background(), "", "") assert.Regexp(t, "FF00138", err) } func TestGetData(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetData", mock.Anything, mock.Anything).Return(core.DataArray{}, nil, nil) fb := database.DataQueryFactory.NewFilter(context.Background()) @@ -554,7 +516,6 @@ func TestGetData(t *testing.T) { func TestGetDatatypeByID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetDatatypeByID", mock.Anything, u).Return(&core.Datatype{ Namespace: "ns1", @@ -565,14 +526,12 @@ func TestGetDatatypeByID(t *testing.T) { func TestGetDatatypeByIDBadID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, err := or.GetDatatypeByID(context.Background(), "", "") assert.Regexp(t, "FF00138", err) } func TestGetDatatypeByName(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi or.mdi.On("GetDatatypeByName", context.Background(), "ns1", "dt", "1").Return(&core.Datatype{ Namespace: "ns1", }, nil) @@ -582,21 +541,18 @@ func TestGetDatatypeByName(t *testing.T) { func TestGetDatatypeByNameBadNamespace(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, err := or.GetDatatypeByName(context.Background(), "", "", "") assert.Regexp(t, "FF00140", err) } func TestGetDatatypeByNameBadName(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, err := or.GetDatatypeByName(context.Background(), "ns1", "", "") assert.Regexp(t, "FF00140", err) } func TestGetOperationByID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetOperationByID", mock.Anything, u).Return(nil, nil) _, err := or.GetOperationByID(context.Background(), u.String()) @@ -605,7 +561,6 @@ func TestGetOperationByID(t *testing.T) { func TestGetOperationByIDNamespaced(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetOperationByID", mock.Anything, u).Return(&core.Operation{ Namespace: "ns1", @@ -616,21 +571,18 @@ func TestGetOperationByIDNamespaced(t *testing.T) { func TestGetOperationIDBadID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, err := or.GetOperationByID(context.Background(), "") assert.Regexp(t, "FF00138", err) } func TestGetOperationIDNamespacedBadID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, err := or.GetOperationByIDNamespaced(context.Background(), "", "") assert.Regexp(t, "FF00138", err) } func TestGetEventByID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetEventByID", mock.Anything, u).Return(&core.Event{ Namespace: "ns1", @@ -641,14 +593,12 @@ func TestGetEventByID(t *testing.T) { func TestGetEventIDBadID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, err := or.GetEventByID(context.Background(), "", "") assert.Regexp(t, "FF00138", err) } func TestGetDatatypes(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetDatatypes", mock.Anything, mock.Anything).Return([]*core.Datatype{}, nil, nil) fb := database.DatatypeQueryFactory.NewFilter(context.Background()) @@ -659,7 +609,6 @@ func TestGetDatatypes(t *testing.T) { func TestGetOperations(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetOperations", mock.Anything, mock.Anything).Return([]*core.Operation{}, nil, nil) fb := database.OperationQueryFactory.NewFilter(context.Background()) @@ -670,7 +619,6 @@ func TestGetOperations(t *testing.T) { func TestGetOperationsNamespaced(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetOperations", mock.Anything, mock.Anything).Return([]*core.Operation{}, nil, nil) fb := database.OperationQueryFactory.NewFilter(context.Background()) @@ -681,7 +629,6 @@ func TestGetOperationsNamespaced(t *testing.T) { func TestGetEvents(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetEvents", mock.Anything, mock.Anything).Return([]*core.Event{}, nil, nil) fb := database.EventQueryFactory.NewFilter(context.Background()) @@ -692,7 +639,6 @@ func TestGetEvents(t *testing.T) { func TestGetEventsWithReferencesFail(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetEvents", mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("pop")) fb := database.EventQueryFactory.NewFilter(context.Background()) @@ -703,7 +649,6 @@ func TestGetEventsWithReferencesFail(t *testing.T) { func TestGetEventsWithReferences(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() // Setup the IDs @@ -771,7 +716,6 @@ func TestGetEventsWithReferences(t *testing.T) { func TestGetEventsWithReferencesEnrichFail(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetEvents", mock.Anything, mock.Anything).Return([]*core.Event{{ID: fftypes.NewUUID()}}, nil, nil) @@ -784,7 +728,6 @@ func TestGetEventsWithReferencesEnrichFail(t *testing.T) { func TestGetBlockchainEventByID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi id := fftypes.NewUUID() or.mdi.On("GetBlockchainEventByID", context.Background(), id).Return(&core.BlockchainEvent{ @@ -797,14 +740,12 @@ func TestGetBlockchainEventByID(t *testing.T) { func TestGetBlockchainEventByIDBadID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, err := or.GetBlockchainEventByID(context.Background(), "ns1", "") assert.Regexp(t, "FF00138", err) } func TestGetBlockchainEvents(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi or.mdi.On("GetBlockchainEvents", context.Background(), mock.Anything).Return(nil, nil, nil) @@ -815,7 +756,6 @@ func TestGetBlockchainEvents(t *testing.T) { func TestGetTransactionBlockchainEventsOk(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi or.mdi.On("GetBlockchainEvents", mock.Anything, mock.Anything).Return([]*core.BlockchainEvent{}, nil, nil) _, _, err := or.GetTransactionBlockchainEvents(context.Background(), "ns1", fftypes.NewUUID().String()) assert.NoError(t, err) @@ -823,14 +763,12 @@ func TestGetTransactionBlockchainEventsOk(t *testing.T) { func TestGetTransactionBlockchainEventsBadID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi _, _, err := or.GetTransactionBlockchainEvents(context.Background(), "ns1", "") assert.Regexp(t, "FF00138", err) } func TestGetPins(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetPins", mock.Anything, mock.Anything).Return([]*core.Pin{}, nil, nil) fb := database.PinQueryFactory.NewFilter(context.Background()) diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index c2fbb13219..22aead3f7c 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -18,19 +18,9 @@ package orchestrator import ( "context" - "fmt" "testing" - "github.com/hyperledger/firefly-common/pkg/config" - "github.com/hyperledger/firefly-common/pkg/ffresty" - "github.com/hyperledger/firefly-common/pkg/fftypes" - "github.com/hyperledger/firefly/internal/blockchain/bifactory" "github.com/hyperledger/firefly/internal/coreconfig" - "github.com/hyperledger/firefly/internal/database/difactory" - "github.com/hyperledger/firefly/internal/dataexchange/dxfactory" - "github.com/hyperledger/firefly/internal/identity/iifactory" - "github.com/hyperledger/firefly/internal/sharedstorage/ssfactory" - "github.com/hyperledger/firefly/internal/tokens/tifactory" "github.com/hyperledger/firefly/mocks/admineventsmocks" "github.com/hyperledger/firefly/mocks/assetmocks" "github.com/hyperledger/firefly/mocks/batchmocks" @@ -46,7 +36,6 @@ import ( "github.com/hyperledger/firefly/mocks/identitymanagermocks" "github.com/hyperledger/firefly/mocks/identitymocks" "github.com/hyperledger/firefly/mocks/metricsmocks" - "github.com/hyperledger/firefly/mocks/namespacemocks" "github.com/hyperledger/firefly/mocks/networkmapmocks" "github.com/hyperledger/firefly/mocks/operationmocks" "github.com/hyperledger/firefly/mocks/privatemessagingmocks" @@ -54,15 +43,7 @@ import ( "github.com/hyperledger/firefly/mocks/sharedstoragemocks" "github.com/hyperledger/firefly/mocks/tokenmocks" "github.com/hyperledger/firefly/mocks/txcommonmocks" - "github.com/hyperledger/firefly/pkg/blockchain" - "github.com/hyperledger/firefly/pkg/core" - "github.com/hyperledger/firefly/pkg/database" - "github.com/hyperledger/firefly/pkg/dataexchange" - "github.com/hyperledger/firefly/pkg/identity" - "github.com/hyperledger/firefly/pkg/sharedstorage" - "github.com/hyperledger/firefly/pkg/tokens" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" ) const configDir = "../../test/data/config" @@ -92,7 +73,6 @@ type testOrchestrator struct { msd *shareddownloadmocks.Manager mae *admineventsmocks.Manager mdh *definitionsmocks.DefinitionHandler - mns *namespacemocks.Manager } func (tor *testOrchestrator) cleanup(t *testing.T) { @@ -118,7 +98,6 @@ func (tor *testOrchestrator) cleanup(t *testing.T) { tor.msd.AssertExpectations(t) tor.mae.AssertExpectations(t) tor.mdh.AssertExpectations(t) - tor.mns.AssertExpectations(t) } func newTestOrchestrator() *testOrchestrator { @@ -126,9 +105,8 @@ func newTestOrchestrator() *testOrchestrator { ctx, cancel := context.WithCancel(context.Background()) tor := &testOrchestrator{ orchestrator: orchestrator{ - ctx: ctx, - cancelCtx: cancel, - pluginNames: make(map[string]bool), + ctx: ctx, + cancelCtx: cancel, }, mdi: &databasemocks.Plugin{}, mdm: &datamocks.Manager{}, @@ -152,23 +130,22 @@ func newTestOrchestrator() *testOrchestrator { msd: &shareddownloadmocks.Manager{}, mae: &admineventsmocks.Manager{}, mdh: &definitionsmocks.DefinitionHandler{}, - mns: &namespacemocks.Manager{}, } - tor.orchestrator.databases = map[string]database.Plugin{"postgres": tor.mdi} + tor.orchestrator.database.Plugin = tor.mdi tor.orchestrator.data = tor.mdm tor.orchestrator.batch = tor.mba tor.orchestrator.broadcast = tor.mbm tor.orchestrator.events = tor.mem tor.orchestrator.networkmap = tor.mnm - tor.orchestrator.sharedstoragePlugins = map[string]sharedstorage.Plugin{"ipfs": tor.mps} + tor.orchestrator.sharedstorage.Plugin = tor.mps tor.orchestrator.messaging = tor.mpm tor.orchestrator.identity = tor.mim - tor.orchestrator.identityPlugins = map[string]identity.Plugin{"identity": tor.mii} - tor.orchestrator.dataexchangePlugins = map[string]dataexchange.Plugin{"ffdx": tor.mdx} + tor.orchestrator.idPlugin.Plugin = tor.mii + tor.orchestrator.dataexchange.Plugin = tor.mdx tor.orchestrator.assets = tor.mam tor.orchestrator.contracts = tor.mcm - tor.orchestrator.tokens = map[string]tokens.Plugin{"token": tor.mti} - tor.orchestrator.blockchains = map[string]blockchain.Plugin{"ethereum": tor.mbi} + tor.orchestrator.tokens = map[string]TokensPlugin{"token": {Plugin: tor.mti}} + tor.orchestrator.blockchain.Plugin = tor.mbi tor.orchestrator.metrics = tor.mmi tor.orchestrator.operations = tor.mom tor.orchestrator.batchpin = tor.mbp @@ -176,7 +153,6 @@ func newTestOrchestrator() *testOrchestrator { tor.orchestrator.adminEvents = tor.mae tor.orchestrator.txHelper = tor.mth tor.orchestrator.definitions = tor.mdh - tor.orchestrator.namespace = tor.mns tor.mdi.On("Name").Return("mock-di").Maybe() tor.mem.On("Name").Return("mock-ei").Maybe() tor.mps.On("Name").Return("mock-ps").Maybe() @@ -191,10 +167,20 @@ func newTestOrchestrator() *testOrchestrator { } func TestNewOrchestrator(t *testing.T) { - or := NewOrchestrator(true) + or := NewOrchestrator( + "ns1", + BlockchainPlugin{}, + DatabasePlugin{}, + SharedStoragePlugin{}, + DataexchangePlugin{}, + map[string]TokensPlugin{}, + IdentityPlugin{}, + &metricsmocks.Manager{}, + ) assert.NotNil(t, or) } +/* func TestBadDeprecatedDatabasePlugin(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) @@ -1172,3 +1158,4 @@ func TestNetworkActionBadType(t *testing.T) { err := or.SubmitNetworkAction(context.Background(), &core.NetworkAction{Type: "bad"}) assert.Regexp(t, "FF10397", err) } +*/ diff --git a/internal/orchestrator/status_test.go b/internal/orchestrator/status_test.go index 69706df2af..081d54b68a 100644 --- a/internal/orchestrator/status_test.go +++ b/internal/orchestrator/status_test.go @@ -35,19 +35,16 @@ var ( pluginsResult = core.NodeStatusPlugins{ Blockchain: []*core.NodeStatusPlugin{ { - Name: "ethereum", PluginType: "mock-bi", }, }, Database: []*core.NodeStatusPlugin{ { - Name: "postgres", PluginType: "mock-di", }, }, DataExchange: []*core.NodeStatusPlugin{ { - Name: "ffdx", PluginType: "mock-dx", }, }, @@ -58,13 +55,11 @@ var ( }, Identity: []*core.NodeStatusPlugin{ { - Name: "identity", PluginType: "mock-ii", }, }, SharedStorage: []*core.NodeStatusPlugin{ { - Name: "ipfs", PluginType: "mock-ps", }, }, diff --git a/internal/orchestrator/subscriptions_test.go b/internal/orchestrator/subscriptions_test.go index ac452bb425..6a4d60e432 100644 --- a/internal/orchestrator/subscriptions_test.go +++ b/internal/orchestrator/subscriptions_test.go @@ -94,7 +94,6 @@ func TestCreateUpdateSubscriptionOk(t *testing.T) { } func TestDeleteSubscriptionBadUUID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi or.mdi.On("GetSubscriptionByID", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("pop")) err := or.DeleteSubscription(or.ctx, "ns2", "! a UUID") assert.Regexp(t, "FF00138", err) @@ -102,7 +101,6 @@ func TestDeleteSubscriptionBadUUID(t *testing.T) { func TestDeleteSubscriptionLookupError(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi or.mdi.On("GetSubscriptionByID", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("pop")) err := or.DeleteSubscription(or.ctx, "ns2", fftypes.NewUUID().String()) assert.EqualError(t, err, "pop") @@ -110,7 +108,6 @@ func TestDeleteSubscriptionLookupError(t *testing.T) { func TestDeleteSubscriptionNSMismatch(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi sub := &core.Subscription{ SubscriptionRef: core.SubscriptionRef{ ID: fftypes.NewUUID(), @@ -125,7 +122,6 @@ func TestDeleteSubscriptionNSMismatch(t *testing.T) { func TestDeleteSubscription(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi sub := &core.Subscription{ SubscriptionRef: core.SubscriptionRef{ ID: fftypes.NewUUID(), @@ -142,7 +138,6 @@ func TestDeleteSubscription(t *testing.T) { func TestGetSubscriptions(t *testing.T) { or := newTestOrchestrator() u := fftypes.NewUUID() - or.databases["database_0"] = or.mdi or.mdi.On("GetSubscriptions", mock.Anything, mock.Anything).Return([]*core.Subscription{}, nil, nil) fb := database.SubscriptionQueryFactory.NewFilter(context.Background()) f := fb.And(fb.Eq("id", u)) @@ -152,7 +147,6 @@ func TestGetSubscriptions(t *testing.T) { func TestGetSGetSubscriptionsByID(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi u := fftypes.NewUUID() or.mdi.On("GetSubscriptionByID", mock.Anything, u).Return(nil, nil) _, err := or.GetSubscriptionByID(context.Background(), "ns1", u.String()) diff --git a/internal/orchestrator/txn_status_test.go b/internal/orchestrator/txn_status_test.go index e2d69a98f9..01bdd8a624 100644 --- a/internal/orchestrator/txn_status_test.go +++ b/internal/orchestrator/txn_status_test.go @@ -39,7 +39,6 @@ func compactJSON(s string) string { func TestGetTransactionStatusBatchPinSuccess(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -120,7 +119,6 @@ func TestGetTransactionStatusBatchPinSuccess(t *testing.T) { func TestGetTransactionStatusBatchPinFail(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -175,7 +173,6 @@ func TestGetTransactionStatusBatchPinFail(t *testing.T) { func TestGetTransactionStatusBatchPinPending(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -230,7 +227,6 @@ func TestGetTransactionStatusBatchPinPending(t *testing.T) { func TestGetTransactionStatusTokenPoolSuccess(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -310,7 +306,6 @@ func TestGetTransactionStatusTokenPoolSuccess(t *testing.T) { func TestGetTransactionStatusTokenPoolPending(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -361,7 +356,6 @@ func TestGetTransactionStatusTokenPoolPending(t *testing.T) { func TestGetTransactionStatusTokenPoolUnconfirmed(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -422,7 +416,6 @@ func TestGetTransactionStatusTokenPoolUnconfirmed(t *testing.T) { func TestGetTransactionStatusTokenTransferSuccess(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -501,7 +494,6 @@ func TestGetTransactionStatusTokenTransferSuccess(t *testing.T) { func TestGetTransactionStatusTokenApprovalSuccess(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -576,7 +568,6 @@ func TestGetTransactionStatusTokenApprovalSuccess(t *testing.T) { func TestGetTransactionStatusTokenTransferPending(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -631,7 +622,6 @@ func TestGetTransactionStatusTokenTransferPending(t *testing.T) { func TestGetTransactionStatusTokenTransferRetry(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -699,7 +689,6 @@ func TestGetTransactionStatusTokenTransferRetry(t *testing.T) { func TestGetTransactionStatusTokenApprovalPending(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -754,7 +743,6 @@ func TestGetTransactionStatusTokenApprovalPending(t *testing.T) { func TestGetTransactionStatusContractInvokeSuccess(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -801,7 +789,6 @@ func TestGetTransactionStatusContractInvokeSuccess(t *testing.T) { func TestGetTransactionStatusTXError(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() or.mdi.On("GetTransactionByID", mock.Anything, txID).Return(nil, fmt.Errorf("pop")) @@ -814,7 +801,6 @@ func TestGetTransactionStatusTXError(t *testing.T) { func TestGetTransactionStatusNotFound(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() or.mdi.On("GetTransactionByID", mock.Anything, txID).Return(nil, nil) @@ -827,7 +813,6 @@ func TestGetTransactionStatusNotFound(t *testing.T) { func TestGetTransactionStatusOpError(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() or.mdi.On("GetTransactionByID", mock.Anything, txID).Return(&core.Transaction{ @@ -843,7 +828,6 @@ func TestGetTransactionStatusOpError(t *testing.T) { func TestGetTransactionStatusBlockchainEventError(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() or.mdi.On("GetTransactionByID", mock.Anything, txID).Return(&core.Transaction{ @@ -860,7 +844,6 @@ func TestGetTransactionStatusBlockchainEventError(t *testing.T) { func TestGetTransactionStatusBatchError(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -881,7 +864,6 @@ func TestGetTransactionStatusBatchError(t *testing.T) { func TestGetTransactionStatusPoolError(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -902,7 +884,6 @@ func TestGetTransactionStatusPoolError(t *testing.T) { func TestGetTransactionStatusTransferError(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -923,7 +904,6 @@ func TestGetTransactionStatusTransferError(t *testing.T) { func TestGetTransactionStatusApprovalError(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ @@ -944,7 +924,6 @@ func TestGetTransactionStatusApprovalError(t *testing.T) { func TestGetTransactionStatusUnknownType(t *testing.T) { or := newTestOrchestrator() - or.databases["database_0"] = or.mdi txID := fftypes.NewUUID() tx := &core.Transaction{ From 3a15d6c6825b02ef0de4265e00f50e70f0cfb79c Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 3 Jun 2022 14:01:33 -0400 Subject: [PATCH 05/33] Resolve circular dependencies in new tree Most of the orchestrator and namespace manager tests are disabled, but the rest of the tests now pass. Signed-off-by: Andrew Richardson --- docs/config_docs_generate_test.go | 4 +- docs/config_docs_test.go | 4 +- docs/swagger/swagger.yaml | 299 --------------------- internal/apiserver/server_test.go | 77 +++--- internal/identity/identitymanager.go | 25 +- internal/identity/identitymanager_test.go | 61 +---- internal/metrics/metrics.go | 1 - internal/namespace/manager.go | 43 ++- internal/namespace/manager_test.go | 47 ++-- internal/networkmap/manager.go | 11 +- internal/networkmap/manager_test.go | 6 +- internal/networkmap/register_org.go | 11 +- internal/networkmap/register_org_test.go | 20 +- internal/orchestrator/orchestrator.go | 17 +- internal/orchestrator/orchestrator_test.go | 2 + internal/orchestrator/status.go | 2 +- internal/orchestrator/status_test.go | 19 +- 17 files changed, 157 insertions(+), 492 deletions(-) diff --git a/docs/config_docs_generate_test.go b/docs/config_docs_generate_test.go index fe2b7d880c..16ca190ea6 100644 --- a/docs/config_docs_generate_test.go +++ b/docs/config_docs_generate_test.go @@ -27,13 +27,13 @@ import ( "github.com/hyperledger/firefly-common/pkg/config" "github.com/hyperledger/firefly/internal/apiserver" - "github.com/hyperledger/firefly/internal/orchestrator" + "github.com/hyperledger/firefly/internal/namespace" "github.com/stretchr/testify/assert" ) func TestGenerateConfigDocs(t *testing.T) { // Initialize config of all plugins - orchestrator.NewOrchestrator(false) + namespace.NewNamespaceManager(false) apiserver.InitConfig() f, err := os.Create(filepath.Join("reference", "config.md")) assert.NoError(t, err) diff --git a/docs/config_docs_test.go b/docs/config_docs_test.go index 0fa852e02c..22b003930d 100644 --- a/docs/config_docs_test.go +++ b/docs/config_docs_test.go @@ -28,13 +28,13 @@ import ( "github.com/hyperledger/firefly-common/pkg/config" "github.com/hyperledger/firefly/internal/apiserver" - "github.com/hyperledger/firefly/internal/orchestrator" + "github.com/hyperledger/firefly/internal/namespace" "github.com/stretchr/testify/assert" ) func TestConfigDocsUpToDate(t *testing.T) { // Initialize config of all plugins - orchestrator.NewOrchestrator(false) + namespace.NewNamespaceManager(false) apiserver.InitConfig() generatedConfig, err := config.GenerateConfigMarkdown(context.Background(), config.GetKnownKeys()) assert.NoError(t, err) diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 11bcf8e618..6cf475aeca 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -26917,305 +26917,6 @@ paths: description: "" tags: - Default Namespace - /status/batchmanager: - get: - description: Gets the status of the batch manager - operationId: getStatusBatchManager - parameters: - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout - schema: - default: 2m0s - type: string - responses: - "200": - content: - application/json: - schema: - properties: - processors: - description: An array of currently active batch processors - items: - description: An array of currently active batch processors - properties: - dispatcher: - description: The type of dispatcher for this processor - type: string - name: - description: The name of the processor, which includes details - of the attributes of message are allocated to this processor - type: string - status: - description: The flush status for this batch processor - properties: - averageBatchBytes: - description: The average byte size of each batch - format: int64 - type: integer - averageBatchData: - description: The average number of data attachments - included in each batch - format: double - type: number - averageBatchMessages: - description: The average number of messages included - in each batch - format: double - type: number - averageFlushTimeMS: - description: The average amount of time spent flushing - each batch - format: int64 - type: integer - blocked: - description: True if the batch flush is in a retry loop, - due to errors being returned by the plugins - type: boolean - flushing: - description: If a flush is in progress, this is the - UUID of the batch being flushed - format: uuid - type: string - lastFlushError: - description: The last error received by this batch processor - while flushing - type: string - lastFlushErrorTime: - description: The time of the last flush - format: date-time - type: string - lastFlushStartTime: - description: The last time a flush was performed - format: date-time - type: string - totalBatches: - description: The total count of batches flushed by this - processor since it started - format: int64 - type: integer - totalErrors: - description: The total count of error flushed encountered - by this processor since it started - format: int64 - type: integer - type: object - type: object - type: array - type: object - description: Success - default: - description: "" - tags: - - Global - /status/pins: - get: - description: Queries the pins table that is the status of the event aggregator - operationId: getStatusPins - parameters: - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout - schema: - default: 2m0s - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: batch - 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: dispatched - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: hash - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: index - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: masked - schema: - type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: sequence - 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: - batch: - description: The UUID of the batch of messages this pin is part - of - format: uuid - type: string - batchHash: - description: The manifest hash batch of messages this pin is - part of - format: byte - type: string - created: - description: The time the FireFly node created the pin - format: date-time - type: string - dispatched: - description: Once true, this pin has been processed and will - not be processed again - type: boolean - hash: - description: The hash represents a topic within a message in - the batch. If a message has multiple topics, then multiple - pins are created. If the message is private, the hash is masked - for privacy - format: byte - type: string - index: - description: The index of this pin within the batch. One pin - is created for each topic, of each message in the batch - format: int64 - type: integer - masked: - description: True if the pin is for a private message, and hence - is masked with the group ID and salted with a nonce so observers - of the blockchain cannot use pin hash to match this transaction - to other transactions or participants - type: boolean - sequence: - description: The order of the pin in the local FireFly database, - which matches the order in which pins were delivered to FireFly - by the blockchain connector event stream - format: int64 - type: integer - signer: - description: The blockchain signing key that submitted this - transaction, as passed through to FireFly by the smart contract - that emitted the blockchain event - type: string - type: object - type: array - description: Success - default: - description: "" - tags: - - Global - /status/websockets: - get: - description: Gets the status of the current WebSocket connections to this node - operationId: getStatusWebSockets - parameters: - - description: Server-side request timeout (milliseconds, or set a custom suffix - like 10s) - in: header - name: Request-Timeout - schema: - default: 2m0s - type: string - responses: - "200": - content: - application/json: - schema: - properties: - connections: - description: List of currently active websocket client connections - items: - description: List of currently active websocket client connections - properties: - id: - description: The unique ID assigned to this client connection - type: string - remoteAddress: - description: The remote address of the connected client - (if available) - type: string - subscriptions: - description: List of subscriptions currently started by - this client - items: - description: List of subscriptions currently started by - this client - properties: - ephemeral: - description: Indicates whether the subscription is - ephemeral (vs durable) - type: boolean - name: - description: The subscription name (for durable subscriptions - only) - type: string - namespace: - description: The subscription namespace - type: string - type: object - type: array - userAgent: - description: The user agent of the connected client (if - available) - type: string - type: object - type: array - enabled: - description: Indicates whether the websockets plugin is enabled - type: boolean - type: object - description: Success - default: - description: "" - tags: - - Global /subscriptions: get: description: Gets a list of subscriptions diff --git a/internal/apiserver/server_test.go b/internal/apiserver/server_test.go index 95dd739af2..bd7e7d1d5f 100644 --- a/internal/apiserver/server_test.go +++ b/internal/apiserver/server_test.go @@ -36,6 +36,7 @@ import ( "github.com/hyperledger/firefly/mocks/admineventsmocks" "github.com/hyperledger/firefly/mocks/apiservermocks" "github.com/hyperledger/firefly/mocks/contractmocks" + "github.com/hyperledger/firefly/mocks/namespacemocks" "github.com/hyperledger/firefly/mocks/orchestratormocks" "github.com/hyperledger/firefly/pkg/core" "github.com/stretchr/testify/assert" @@ -44,31 +45,33 @@ import ( const configDir = "../../test/data/config" -func newTestServer() (*orchestratormocks.Orchestrator, *apiServer) { +func newTestServer() (*namespacemocks.Manager, *orchestratormocks.Orchestrator, *apiServer) { coreconfig.Reset() InitConfig() - mor := &orchestratormocks.Orchestrator{} + mgr := &namespacemocks.Manager{} + o := &orchestratormocks.Orchestrator{} + mgr.On("Orchestrator", mock.Anything).Return(o) as := &apiServer{ apiTimeout: 5 * time.Second, maxFilterLimit: 100, ffiSwaggerGen: &apiservermocks.FFISwaggerGen{}, } - return mor, as + return mgr, o, as } func newTestAPIServer() (*orchestratormocks.Orchestrator, *mux.Router) { - mor, as := newTestServer() - r := as.createMuxRouter(context.Background(), mor) - return mor, r + mgr, o, as := newTestServer() + r := as.createMuxRouter(context.Background(), mgr) + return o, r } -func newTestAdminServer() (*orchestratormocks.Orchestrator, *mux.Router) { +func newTestAdminServer() (*namespacemocks.Manager, *mux.Router) { config.Set(coreconfig.NamespacesDefault, "default") - mor, as := newTestServer() + mgr, _, as := newTestServer() mae := &admineventsmocks.Manager{} - mor.On("AdminEvents").Return(mae) - r := as.createAdminMuxRouter(mor) - return mor, r + mgr.On("AdminEvents").Return(mae) + r := as.createAdminMuxRouter(mgr) + return mgr, r } func TestStartStopServer(t *testing.T) { @@ -82,10 +85,10 @@ func TestStartStopServer(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() // server will immediately shut down as := NewAPIServer() - mor := &orchestratormocks.Orchestrator{} + mgr := &namespacemocks.Manager{} mae := &admineventsmocks.Manager{} - mor.On("AdminEvents").Return(mae) - err := as.Serve(ctx, mor) + mgr.On("AdminEvents").Return(mae) + err := as.Serve(ctx, mgr) assert.NoError(t, err) } @@ -97,8 +100,8 @@ func TestStartAPIFail(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() // server will immediately shut down as := NewAPIServer() - mor := &orchestratormocks.Orchestrator{} - err := as.Serve(ctx, mor) + mgr := &namespacemocks.Manager{} + err := as.Serve(ctx, mgr) assert.Regexp(t, "FF00151", err) } @@ -111,10 +114,10 @@ func TestStartAdminFail(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() // server will immediately shut down as := NewAPIServer() - mor := &orchestratormocks.Orchestrator{} + mgr := &namespacemocks.Manager{} mae := &admineventsmocks.Manager{} - mor.On("AdminEvents").Return(mae) - err := as.Serve(ctx, mor) + mgr.On("AdminEvents").Return(mae) + err := as.Serve(ctx, mgr) assert.Regexp(t, "FF00151", err) } @@ -125,15 +128,15 @@ func TestStartAdminWSHandler(t *testing.T) { adminConfig.Set(httpserver.HTTPConfAddress, "...://") config.Set(coreconfig.AdminEnabled, true) as := NewAPIServer().(*apiServer) - mor := &orchestratormocks.Orchestrator{} + mgr := &namespacemocks.Manager{} mae := &admineventsmocks.Manager{} - mor.On("AdminEvents").Return(mae) + mgr.On("AdminEvents").Return(mae) mae.On("ServeHTTPWebSocketListener", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { res := args[0].(http.ResponseWriter) res.WriteHeader(200) }).Return() res := httptest.NewRecorder() - as.adminWSHandler(mor).ServeHTTP(res, httptest.NewRequest("GET", "/", nil)) + as.adminWSHandler(mgr).ServeHTTP(res, httptest.NewRequest("GET", "/", nil)) assert.Equal(t, 200, res.Result().StatusCode) } @@ -146,15 +149,15 @@ func TestStartMetricsFail(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() // server will immediately shut down as := NewAPIServer() - mor := &orchestratormocks.Orchestrator{} + mgr := &namespacemocks.Manager{} mae := &admineventsmocks.Manager{} - mor.On("AdminEvents").Return(mae) - err := as.Serve(ctx, mor) + mgr.On("AdminEvents").Return(mae) + err := as.Serve(ctx, mgr) assert.Regexp(t, "FF00151", err) } func TestNotFound(t *testing.T) { - _, as := newTestServer() + _, _, as := newTestServer() handler := as.handlerFactory().APIWrapper(as.notFoundHandler) s := httptest.NewServer(http.HandlerFunc(handler)) defer s.Close() @@ -168,8 +171,8 @@ func TestNotFound(t *testing.T) { } func TestFilterTooMany(t *testing.T) { - mor, as := newTestServer() - handler := as.routeHandler(as.handlerFactory(), mor, "", getBatches) + mgr, _, as := newTestServer() + handler := as.routeHandler(as.handlerFactory(), mgr, "", getBatches) req := httptest.NewRequest("GET", "http://localhost:12345/test?limit=99999999999", nil) res := httptest.NewRecorder() @@ -181,7 +184,7 @@ func TestFilterTooMany(t *testing.T) { } func TestSwaggerYAML(t *testing.T) { - _, as := newTestServer() + _, _, as := newTestServer() handler := as.handlerFactory().APIWrapper(as.swaggerHandler(as.swaggerGenerator(routes, "http://localhost:12345/api/v1"))) s := httptest.NewServer(http.HandlerFunc(handler)) defer s.Close() @@ -243,8 +246,8 @@ func TestWaitForServerStop(t *testing.T) { } func TestContractAPISwaggerJSON(t *testing.T) { - o, as := newTestServer() - r := as.createMuxRouter(context.Background(), o) + mgr, o, as := newTestServer() + r := as.createMuxRouter(context.Background(), mgr) mcm := &contractmocks.Manager{} o.On("Contracts").Return(mcm) mffi := as.ffiSwaggerGen.(*apiservermocks.FFISwaggerGen) @@ -268,8 +271,8 @@ func TestContractAPISwaggerJSON(t *testing.T) { } func TestContractAPISwaggerJSONGetAPIFail(t *testing.T) { - o, as := newTestServer() - r := as.createMuxRouter(context.Background(), o) + mgr, o, as := newTestServer() + r := as.createMuxRouter(context.Background(), mgr) mcm := &contractmocks.Manager{} o.On("Contracts").Return(mcm) s := httptest.NewServer(r) @@ -283,8 +286,8 @@ func TestContractAPISwaggerJSONGetAPIFail(t *testing.T) { } func TestContractAPISwaggerJSONGetAPINotFound(t *testing.T) { - o, as := newTestServer() - r := as.createMuxRouter(context.Background(), o) + mgr, o, as := newTestServer() + r := as.createMuxRouter(context.Background(), mgr) mcm := &contractmocks.Manager{} o.On("Contracts").Return(mcm) s := httptest.NewServer(r) @@ -298,8 +301,8 @@ func TestContractAPISwaggerJSONGetAPINotFound(t *testing.T) { } func TestContractAPISwaggerJSONGetFFIFail(t *testing.T) { - o, as := newTestServer() - r := as.createMuxRouter(context.Background(), o) + mgr, o, as := newTestServer() + r := as.createMuxRouter(context.Background(), mgr) mcm := &contractmocks.Manager{} o.On("Contracts").Return(mcm) s := httptest.NewServer(r) diff --git a/internal/identity/identitymanager.go b/internal/identity/identitymanager.go index d3d0ff4712..5103bd40f9 100644 --- a/internal/identity/identitymanager.go +++ b/internal/identity/identitymanager.go @@ -61,6 +61,9 @@ type identityManager struct { blockchain blockchain.Plugin data data.Manager + defaultKey string + orgName string + orgKey string multipartyRootVerifier map[string]*core.VerifierRef multipartyRootOrg map[string]*core.Identity identityCacheTTL time.Duration @@ -69,7 +72,7 @@ type identityManager struct { signingKeyCache *ccache.Cache } -func NewIdentityManager(ctx context.Context, di database.Plugin, ii identity.Plugin, bi blockchain.Plugin, dm data.Manager) (Manager, error) { +func NewIdentityManager(ctx context.Context, defaultKey, orgName, orgKey string, di database.Plugin, ii identity.Plugin, bi blockchain.Plugin, dm data.Manager) (Manager, error) { if di == nil || ii == nil || bi == nil { return nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError, "IdentityManager") } @@ -78,6 +81,9 @@ func NewIdentityManager(ctx context.Context, di database.Plugin, ii identity.Plu plugin: ii, blockchain: bi, data: dm, + defaultKey: defaultKey, + orgName: orgName, + orgKey: orgKey, multipartyRootVerifier: make(map[string]*core.VerifierRef), multipartyRootOrg: make(map[string]*core.Identity), identityCacheTTL: config.GetDuration(coreconfig.IdentityManagerCacheTTL), @@ -228,9 +234,8 @@ func (im *identityManager) resolveDefaultSigningIdentity(ctx context.Context, na // getDefaultVerifier gets the default blockchain verifier via the configuration func (im *identityManager) getDefaultVerifier(ctx context.Context, namespace string) (verifier *core.VerifierRef, err error) { - defaultKey := im.namespace.GetDefaultKey(namespace) - if defaultKey != "" { - return im.normalizeKeyViaBlockchainPlugin(ctx, defaultKey) + if im.defaultKey != "" { + return im.normalizeKeyViaBlockchainPlugin(ctx, im.defaultKey) } return im.GetMultipartyRootVerifier(ctx, namespace) } @@ -241,12 +246,11 @@ func (im *identityManager) GetMultipartyRootVerifier(ctx context.Context, namesp return key, nil } - orgKey := im.namespace.GetMultipartyConfig(namespace, coreconfig.OrgKey) - if orgKey == "" { + if im.orgKey == "" { return nil, i18n.NewError(ctx, coremsgs.MsgNodeMissingBlockchainKey) } - verifier, err := im.normalizeKeyViaBlockchainPlugin(ctx, orgKey) + verifier, err := im.normalizeKeyViaBlockchainPlugin(ctx, im.orgKey) if err != nil { return nil, err } @@ -294,14 +298,13 @@ func (im *identityManager) GetMultipartyRootOrg(ctx context.Context, namespace s return nil, err } - orgName := im.namespace.GetMultipartyConfig(namespace, coreconfig.OrgName) identity, err := im.cachedIdentityLookupByVerifierRef(ctx, namespace, verifierRef) if err != nil || identity == nil { - return nil, i18n.WrapError(ctx, err, coremsgs.MsgLocalOrgLookupFailed, orgName, verifierRef.Value) + return nil, i18n.WrapError(ctx, err, coremsgs.MsgLocalOrgLookupFailed, im.orgName, verifierRef.Value) } // Confirm that the specified blockchain key is associated with the correct org - if identity.Type != core.IdentityTypeOrg || identity.Name != orgName { - return nil, i18n.NewError(ctx, coremsgs.MsgLocalOrgLookupFailed, orgName, verifierRef.Value) + if identity.Type != core.IdentityTypeOrg || identity.Name != im.orgName { + return nil, i18n.NewError(ctx, coremsgs.MsgLocalOrgLookupFailed, im.orgName, verifierRef.Value) } im.multipartyRootOrg[namespace] = identity return identity, nil diff --git a/internal/identity/identitymanager_test.go b/internal/identity/identitymanager_test.go index a013eb34c6..06756bce28 100644 --- a/internal/identity/identitymanager_test.go +++ b/internal/identity/identitymanager_test.go @@ -27,9 +27,7 @@ import ( "github.com/hyperledger/firefly/mocks/databasemocks" "github.com/hyperledger/firefly/mocks/datamocks" "github.com/hyperledger/firefly/mocks/identitymocks" - "github.com/hyperledger/firefly/mocks/namespacemocks" "github.com/hyperledger/firefly/pkg/core" - "github.com/hyperledger/firefly/pkg/identity" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -41,20 +39,17 @@ func newTestIdentityManager(t *testing.T) (context.Context, *identityManager) { mii := &identitymocks.Plugin{} mbi := &blockchainmocks.Plugin{} mdm := &datamocks.Manager{} - mns := &namespacemocks.Manager{} mbi.On("VerifierType").Return(core.VerifierTypeEthAddress).Maybe() - plugins := map[string]identity.Plugin{"tbd": mii} - ctx := context.Background() - im, err := NewIdentityManager(ctx, mdi, plugins, mbi, mdm, mns) + im, err := NewIdentityManager(ctx, "", "", "", mdi, mii, mbi, mdm) assert.NoError(t, err) return ctx, im.(*identityManager) } func TestNewIdentityManagerMissingDeps(t *testing.T) { - _, err := NewIdentityManager(context.Background(), nil, nil, nil, nil, nil) + _, err := NewIdentityManager(context.Background(), "", "", "", nil, nil, nil, nil) assert.Regexp(t, "FF10128", err) } @@ -62,26 +57,18 @@ func TestResolveInputSigningIdentityNoKey(t *testing.T) { ctx, im := newTestIdentityManager(t) - mns := im.namespace.(*namespacemocks.Manager) - mns.On("GetDefaultKey", "ns1").Return("") - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgKey).Return("") - msgIdentity := &core.SignerRef{} err := im.ResolveInputSigningIdentity(ctx, "ns1", msgIdentity) assert.Regexp(t, "FF10354", err) - mns.AssertExpectations(t) - } func TestResolveInputSigningIdentityOrgFallbackOk(t *testing.T) { ctx, im := newTestIdentityManager(t) - mns := im.namespace.(*namespacemocks.Manager) - mns.On("GetDefaultKey", "ns1").Return("") - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgName).Return("org1") - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgKey).Return("key123") + im.orgName = "org1" + im.orgKey = "key123" mbi := im.blockchain.(*blockchainmocks.Plugin) mbi.On("NormalizeSigningKey", ctx, "key123").Return("fullkey123", nil) @@ -117,7 +104,6 @@ func TestResolveInputSigningIdentityOrgFallbackOk(t *testing.T) { mbi.AssertExpectations(t) mdi.AssertExpectations(t) - mns.AssertExpectations(t) } @@ -447,8 +433,7 @@ func TestNormalizeSigningKeyDefault(t *testing.T) { ctx, im := newTestIdentityManager(t) - mns := im.namespace.(*namespacemocks.Manager) - mns.On("GetDefaultKey", "ns1").Return("key123") + im.defaultKey = "key123" mbi := im.blockchain.(*blockchainmocks.Plugin) mbi.On("NormalizeSigningKey", ctx, "key123").Return("fullkey123", nil) @@ -458,7 +443,6 @@ func TestNormalizeSigningKeyDefault(t *testing.T) { assert.Equal(t, "fullkey123", resolvedKey) mbi.AssertExpectations(t) - mns.AssertExpectations(t) } @@ -466,9 +450,7 @@ func TestNormalizeSigningKeyOrgFallbackOk(t *testing.T) { ctx, im := newTestIdentityManager(t) - mns := im.namespace.(*namespacemocks.Manager) - mns.On("GetDefaultKey", "ns1").Return("") - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgKey).Return("key123") + im.orgKey = "key123" mbi := im.blockchain.(*blockchainmocks.Plugin) mbi.On("NormalizeSigningKey", ctx, "key123").Return("fullkey123", nil) @@ -478,7 +460,6 @@ func TestNormalizeSigningKeyOrgFallbackOk(t *testing.T) { assert.Equal(t, "fullkey123", resolvedKey) mbi.AssertExpectations(t) - mns.AssertExpectations(t) } @@ -486,9 +467,7 @@ func TestNormalizeSigningKeyOrgFallbackErr(t *testing.T) { ctx, im := newTestIdentityManager(t) - mns := im.namespace.(*namespacemocks.Manager) - mns.On("GetDefaultKey", "ns1").Return("") - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgKey).Return("key123") + im.orgKey = "key123" mbi := im.blockchain.(*blockchainmocks.Plugin) mbi.On("NormalizeSigningKey", ctx, "key123").Return("fullkey123", fmt.Errorf("pop")) @@ -497,7 +476,6 @@ func TestNormalizeSigningKeyOrgFallbackErr(t *testing.T) { assert.Regexp(t, "pop", err) mbi.AssertExpectations(t) - mns.AssertExpectations(t) } @@ -577,16 +555,11 @@ func TestResolveDefaultSigningIdentityNotFound(t *testing.T) { mdi.On("GetVerifierByValue", ctx, core.VerifierTypeEthAddress, "ns1", "key12345").Return(nil, nil) mdi.On("GetVerifierByValue", ctx, core.VerifierTypeEthAddress, core.LegacySystemNamespace, "key12345").Return(nil, nil) - mns := im.namespace.(*namespacemocks.Manager) - mns.On("GetDefaultKey", "ns1").Return("") - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgName).Return("org1") - err := im.resolveDefaultSigningIdentity(ctx, "ns1", &core.SignerRef{}) assert.Regexp(t, "FF10281", err) mbi.AssertExpectations(t) mdi.AssertExpectations(t) - mns.AssertExpectations(t) } @@ -622,9 +595,7 @@ func TestResolveDefaultSigningIdentitySystemFallback(t *testing.T) { mdi.On("GetVerifierByValue", ctx, core.VerifierTypeEthAddress, core.LegacySystemNamespace, "key12345").Return(verifier, nil) mdi.On("GetIdentityByID", ctx, id.ID).Return(id, nil) - mns := im.namespace.(*namespacemocks.Manager) - mns.On("GetDefaultKey", "ns1").Return("") - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgName).Return("org1") + im.orgName = "org1" ref := &core.SignerRef{} err := im.resolveDefaultSigningIdentity(ctx, "ns1", ref) @@ -634,7 +605,6 @@ func TestResolveDefaultSigningIdentitySystemFallback(t *testing.T) { mbi.AssertExpectations(t) mdi.AssertExpectations(t) - mns.AssertExpectations(t) } @@ -642,15 +612,10 @@ func TestGetMultipartyRootVerifierResolveFailed(t *testing.T) { ctx, im := newTestIdentityManager(t) - mnm := im.namespace.(*namespacemocks.Manager) - mnm.On("GetConfigWithFallback", "ns1", coreconfig.OrgKey).Return("") - mbi := im.blockchain.(*blockchainmocks.Plugin) mbi.On("NormalizeSigningKey", ctx, "0x12345").Return("", fmt.Errorf("pop")) - mns := im.namespace.(*namespacemocks.Manager) - mns.On("GetDefaultKey", "ns1").Return("") - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgKey).Return("0x12345") + im.orgKey = "0x12345" _, err := im.GetMultipartyRootVerifier(ctx, "ns1") assert.Regexp(t, "pop", err) @@ -705,10 +670,6 @@ func TestGetMultipartyRootVerifierNotSet(t *testing.T) { ctx, im := newTestIdentityManager(t) - mns := im.namespace.(*namespacemocks.Manager) - mns.On("GetDefaultKey", "ns1").Return("") - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgKey).Return("") - _, err := im.GetMultipartyRootOrg(ctx, "ns1") assert.Regexp(t, "FF10354", err) @@ -744,10 +705,6 @@ func TestGetMultipartyRootOrgMismatch(t *testing.T) { }, }, nil) - mns := im.namespace.(*namespacemocks.Manager) - mns.On("GetDefaultKey", "ns1").Return("") - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgName).Return("org1") - _, err := im.GetMultipartyRootOrg(ctx, "ns1") assert.Regexp(t, "FF10281", err) diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index f285af0487..98688e727e 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -52,7 +52,6 @@ type metricsManager struct { } func (mm *metricsManager) Start() error { - Registry() // ensure registry is initialized return nil } diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index b792a60701..49e9ba6dd9 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -66,7 +66,8 @@ type Manager interface { type namespace struct { orchestrator orchestrator.Orchestrator - multiparty bool + defaultKey string + multiparty orchestrator.MultipartyConfig database orchestrator.DatabasePlugin blockchain orchestrator.BlockchainPlugin dataexchange orchestrator.DataexchangePlugin @@ -93,6 +94,8 @@ type namespaceManager struct { func NewNamespaceManager(withDefaults bool) Manager { nm := &namespaceManager{} + InitConfig(withDefaults) + // Initialize the config on all the factories bifactory.InitConfigDeprecated(deprecatedBlockchainConfig) bifactory.InitConfig(blockchainConfig) @@ -125,7 +128,7 @@ func (nm *namespaceManager) Init(ctx context.Context, cancelCtx context.CancelFu // Start an orchestrator per namespace for name, ns := range nm.namespaces { - or := orchestrator.NewOrchestrator(name, ns.blockchain, ns.database, ns.sharedstorage, ns.dataexchange, ns.tokens, ns.identity, nm.metrics) + or := orchestrator.NewOrchestrator(name, ns.defaultKey, ns.multiparty, ns.blockchain, ns.database, ns.sharedstorage, ns.dataexchange, ns.tokens, ns.identity, nm.metrics) if err = or.Init(ctx, cancelCtx); err != nil { return err } @@ -513,9 +516,21 @@ func (nm *namespaceManager) buildAndValidateNamespaces(ctx context.Context, name } // If any multiparty org information is configured (here or at the root), assume multiparty mode by default + orgName := conf.GetString(coreconfig.NamespaceMultipartyOrgName) + if orgName == "" { + orgName = config.GetString(coreconfig.OrgName) + } + orgKey := conf.GetString(coreconfig.NamespaceMultipartyOrgKey) + if orgKey == "" { + orgKey = config.GetString(coreconfig.OrgKey) + } + orgDesc := conf.GetString(coreconfig.NamespaceMultipartyOrgDescription) + if orgDesc == "" { + orgDesc = config.GetString(coreconfig.OrgDescription) + } multiparty := conf.Get(coreconfig.NamespaceMultipartyEnabled) if multiparty == nil { - multiparty = nm.GetMultipartyConfig(name, coreconfig.OrgName) != "" || nm.GetMultipartyConfig(name, coreconfig.OrgKey) != "" + multiparty = orgName != "" || orgKey != "" } // If no plugins are listed under this namespace, use all defined plugins by default @@ -538,13 +553,21 @@ func (nm *namespaceManager) buildAndValidateNamespaces(ctx context.Context, name } } + defaultKey := conf.GetString(coreconfig.NamespaceDefaultKey) + if multiparty.(bool) { - return nm.validateMultiPartyConfig(ctx, name, plugins) + config := orchestrator.MultipartyConfig{ + Enabled: true, + OrgName: orgName, + OrgKey: orgKey, + OrgDesc: orgDesc, + } + return nm.validateMultiPartyConfig(ctx, name, defaultKey, config, plugins) } - return nm.validateGatewayConfig(ctx, name, plugins) + return nm.validateGatewayConfig(ctx, name, defaultKey, plugins) } -func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name string, plugins []string) error { +func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name, defaultKey string, config orchestrator.MultipartyConfig, plugins []string) error { var dbPlugin bool var ssPlugin bool var dxPlugin bool @@ -552,7 +575,8 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s ns := namespace{ tokens: make(map[string]orchestrator.TokensPlugin), - multiparty: true, + multiparty: config, + defaultKey: defaultKey, } for _, pluginName := range plugins { @@ -608,12 +632,13 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s return nil } -func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name string, plugins []string) error { +func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name, defaultKey string, plugins []string) error { var dbPlugin bool var bcPlugin bool ns := namespace{ - tokens: make(map[string]orchestrator.TokensPlugin), + tokens: make(map[string]orchestrator.TokensPlugin), + defaultKey: defaultKey, } for _, pluginName := range plugins { diff --git a/internal/namespace/manager_test.go b/internal/namespace/manager_test.go index 32e316b223..e1c3178f69 100644 --- a/internal/namespace/manager_test.go +++ b/internal/namespace/manager_test.go @@ -17,28 +17,16 @@ package namespace import ( - "context" - "fmt" - "strings" "testing" - "github.com/hyperledger/firefly-common/pkg/config" - "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly/internal/coreconfig" + "github.com/hyperledger/firefly/internal/orchestrator" "github.com/hyperledger/firefly/mocks/blockchainmocks" "github.com/hyperledger/firefly/mocks/databasemocks" "github.com/hyperledger/firefly/mocks/dataexchangemocks" "github.com/hyperledger/firefly/mocks/sharedstoragemocks" "github.com/hyperledger/firefly/mocks/tokenmocks" - "github.com/hyperledger/firefly/pkg/blockchain" - "github.com/hyperledger/firefly/pkg/core" - "github.com/hyperledger/firefly/pkg/database" - "github.com/hyperledger/firefly/pkg/dataexchange" - "github.com/hyperledger/firefly/pkg/sharedstorage" - "github.com/hyperledger/firefly/pkg/tokens" - "github.com/spf13/viper" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" ) type testNamespaceManager struct { @@ -62,28 +50,34 @@ func newTestNamespaceManager(resetConfig bool) *testNamespaceManager { nm := &testNamespaceManager{ mdi: &databasemocks.Plugin{}, namespaceManager: namespaceManager{ - nsConfig: buildNamespaceMap(context.Background()), - bcPlugins: map[string]blockchain.Plugin{"ethereum": &blockchainmocks.Plugin{}, "fabric": &blockchainmocks.Plugin{}}, - dbPlugins: map[string]database.Plugin{"postgres": &databasemocks.Plugin{}, "sqlite3": &databasemocks.Plugin{}}, - dxPlugins: map[string]dataexchange.Plugin{"ffdx": &dataexchangemocks.Plugin{}, "ffdx2": &dataexchangemocks.Plugin{}}, - ssPlugins: map[string]sharedstorage.Plugin{"ipfs": &sharedstoragemocks.Plugin{}, "ipfs2": &sharedstoragemocks.Plugin{}}, - tokensPlugins: map[string]tokens.Plugin{"erc721": &tokenmocks.Plugin{}}, + blockchains: map[string]orchestrator.BlockchainPlugin{ + "ethereum": {Plugin: &blockchainmocks.Plugin{}}, + "fabric": {Plugin: &blockchainmocks.Plugin{}}, + }, + databases: map[string]orchestrator.DatabasePlugin{ + "postgres": {Plugin: &databasemocks.Plugin{}}, + "sqlite3": {Plugin: &databasemocks.Plugin{}}, + }, + dataexchanges: map[string]orchestrator.DataexchangePlugin{ + "ffdx": {Plugin: &dataexchangemocks.Plugin{}}, + }, + sharedstorages: map[string]orchestrator.SharedStoragePlugin{ + "ipfs": {Plugin: &sharedstoragemocks.Plugin{}}, + }, + tokens: map[string]orchestrator.TokensPlugin{ + "erc721": {Plugin: &tokenmocks.Plugin{}}, + }, }, } return nm } func TestNewNamespaceManager(t *testing.T) { - bc := map[string]blockchain.Plugin{"ethereum": &blockchainmocks.Plugin{}} - db := map[string]database.Plugin{"postgres": &databasemocks.Plugin{}} - dx := map[string]dataexchange.Plugin{"ffdx": &dataexchangemocks.Plugin{}} - ss := map[string]sharedstorage.Plugin{"ipfs": &sharedstoragemocks.Plugin{}} - tokens := map[string]tokens.Plugin{"erc721": &tokenmocks.Plugin{}} - - nm := NewNamespaceManager(context.Background(), bc, db, dx, ss, tokens) + nm := NewNamespaceManager(true) assert.NotNil(t, nm) } +/* func TestInit(t *testing.T) { coreconfig.Reset() nm := newTestNamespaceManager(false) @@ -479,3 +473,4 @@ func TestGetDefaultKeyNotFound(t *testing.T) { key := nm.GetDefaultKey("ns1") assert.Equal(t, "", key) } +*/ diff --git a/internal/networkmap/manager.go b/internal/networkmap/manager.go index 2bbba05da8..c3d8d9351f 100644 --- a/internal/networkmap/manager.go +++ b/internal/networkmap/manager.go @@ -24,7 +24,6 @@ import ( "github.com/hyperledger/firefly/internal/coremsgs" "github.com/hyperledger/firefly/internal/data" "github.com/hyperledger/firefly/internal/identity" - "github.com/hyperledger/firefly/internal/namespace" "github.com/hyperledger/firefly/internal/syncasync" "github.com/hyperledger/firefly/pkg/core" "github.com/hyperledger/firefly/pkg/database" @@ -58,29 +57,31 @@ type Manager interface { type networkMap struct { ctx context.Context + orgName string + orgDesc string database database.Plugin data data.Manager broadcast broadcast.Manager exchange dataexchange.Plugin identity identity.Manager syncasync syncasync.Bridge - namespace namespace.Manager } -func NewNetworkMap(ctx context.Context, di database.Plugin, dm data.Manager, bm broadcast.Manager, dx dataexchange.Plugin, im identity.Manager, sa syncasync.Bridge, ns namespace.Manager) (Manager, error) { - if di == nil || dm == nil || bm == nil || dx == nil || im == nil || ns == nil { +func NewNetworkMap(ctx context.Context, orgName, orgDesc string, di database.Plugin, dm data.Manager, bm broadcast.Manager, dx dataexchange.Plugin, im identity.Manager, sa syncasync.Bridge) (Manager, error) { + if di == nil || dm == nil || bm == nil || dx == nil || im == nil { return nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError, "NetworkMap") } nm := &networkMap{ ctx: ctx, + orgName: orgName, + orgDesc: orgDesc, database: di, data: dm, broadcast: bm, exchange: dx, identity: im, syncasync: sa, - namespace: ns, } return nm, nil } diff --git a/internal/networkmap/manager_test.go b/internal/networkmap/manager_test.go index 1664633113..ed3b796e25 100644 --- a/internal/networkmap/manager_test.go +++ b/internal/networkmap/manager_test.go @@ -26,7 +26,6 @@ import ( "github.com/hyperledger/firefly/mocks/dataexchangemocks" "github.com/hyperledger/firefly/mocks/datamocks" "github.com/hyperledger/firefly/mocks/identitymanagermocks" - "github.com/hyperledger/firefly/mocks/namespacemocks" "github.com/hyperledger/firefly/mocks/syncasyncmocks" "github.com/stretchr/testify/assert" ) @@ -40,14 +39,13 @@ func newTestNetworkmap(t *testing.T) (*networkMap, func()) { mdx := &dataexchangemocks.Plugin{} mim := &identitymanagermocks.Manager{} msa := &syncasyncmocks.Bridge{} - mns := &namespacemocks.Manager{} - nm, err := NewNetworkMap(ctx, mdi, mdm, mbm, mdx, mim, msa, mns) + nm, err := NewNetworkMap(ctx, "org0", "org0", mdi, mdm, mbm, mdx, mim, msa) assert.NoError(t, err) return nm.(*networkMap), cancel } func TestNewNetworkMapMissingDep(t *testing.T) { - _, err := NewNetworkMap(context.Background(), nil, nil, nil, nil, nil, nil, nil) + _, err := NewNetworkMap(context.Background(), "", "", nil, nil, nil, nil, nil, nil) assert.Regexp(t, "FF10128", err) } diff --git a/internal/networkmap/register_org.go b/internal/networkmap/register_org.go index 11136071e3..ed7682ed5b 100644 --- a/internal/networkmap/register_org.go +++ b/internal/networkmap/register_org.go @@ -20,7 +20,6 @@ import ( "context" "github.com/hyperledger/firefly-common/pkg/i18n" - "github.com/hyperledger/firefly/internal/coreconfig" "github.com/hyperledger/firefly/internal/coremsgs" "github.com/hyperledger/firefly/pkg/core" ) @@ -33,16 +32,16 @@ func (nm *networkMap) RegisterNodeOrganization(ctx context.Context, ns string, w return nil, err } + if nm.orgName == "" { + return nil, i18n.NewError(ctx, coremsgs.MsgNodeAndOrgIDMustBeSet) + } orgRequest := &core.IdentityCreateDTO{ - Name: nm.namespace.GetMultipartyConfig(ns, coreconfig.OrgName), + Name: nm.orgName, IdentityProfile: core.IdentityProfile{ - Description: nm.namespace.GetMultipartyConfig(ns, coreconfig.OrgDescription), + Description: nm.orgDesc, }, Key: key.Value, } - if orgRequest.Name == "" { - return nil, i18n.NewError(ctx, coremsgs.MsgNodeAndOrgIDMustBeSet) - } return nm.RegisterOrganization(ctx, ns, orgRequest, waitConfirm) } diff --git a/internal/networkmap/register_org_test.go b/internal/networkmap/register_org_test.go index 4ce2e6dfec..0854353e79 100644 --- a/internal/networkmap/register_org_test.go +++ b/internal/networkmap/register_org_test.go @@ -21,13 +21,10 @@ import ( "fmt" "testing" - "github.com/hyperledger/firefly-common/pkg/config" "github.com/hyperledger/firefly-common/pkg/fftypes" - "github.com/hyperledger/firefly/internal/coreconfig" "github.com/hyperledger/firefly/mocks/broadcastmocks" "github.com/hyperledger/firefly/mocks/datamocks" "github.com/hyperledger/firefly/mocks/identitymanagermocks" - "github.com/hyperledger/firefly/mocks/namespacemocks" "github.com/hyperledger/firefly/pkg/core" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -60,8 +57,6 @@ func TestRegisterNodeOrgOk(t *testing.T) { nm, cancel := newTestNetworkmap(t) defer cancel() - config.Set(coreconfig.NodeDescription, "Node 1") - mim := nm.identity.(*identitymanagermocks.Manager) mim.On("GetMultipartyRootVerifier", nm.ctx, "ns1").Return(&core.VerifierRef{ Value: "0x12345", @@ -81,10 +76,6 @@ func TestRegisterNodeOrgOk(t *testing.T) { }), core.SystemTagIdentityClaim, false).Return(mockMsg, nil) - mns := nm.namespace.(*namespacemocks.Manager) - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgName).Return("org1") - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgDescription).Return("") - org, err := nm.RegisterNodeOrganization(nm.ctx, "ns1", false) assert.NoError(t, err) assert.Equal(t, *mockMsg.Header.ID, *org.Messages.Claim) @@ -92,7 +83,6 @@ func TestRegisterNodeOrgOk(t *testing.T) { mim.AssertExpectations(t) mbm.AssertExpectations(t) mdm.AssertExpectations(t) - mns.AssertExpectations(t) } func TestRegisterNodeOrgNoName(t *testing.T) { @@ -100,22 +90,17 @@ func TestRegisterNodeOrgNoName(t *testing.T) { nm, cancel := newTestNetworkmap(t) defer cancel() - config.Set(coreconfig.NodeDescription, "") + nm.orgName = "" mim := nm.identity.(*identitymanagermocks.Manager) mim.On("GetMultipartyRootVerifier", nm.ctx, "ns1").Return(&core.VerifierRef{ Value: "0x12345", }, nil) - mns := nm.namespace.(*namespacemocks.Manager) - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgName).Return("") - mns.On("GetMultipartyConfig", "ns1", coreconfig.OrgDescription).Return("") - _, err := nm.RegisterNodeOrganization(nm.ctx, "ns1", false) assert.Regexp(t, "FF10216", err) mim.AssertExpectations(t) - mns.AssertExpectations(t) } func TestRegisterNodeGetOwnerBlockchainKeyFail(t *testing.T) { @@ -123,9 +108,6 @@ func TestRegisterNodeGetOwnerBlockchainKeyFail(t *testing.T) { nm, cancel := newTestNetworkmap(t) defer cancel() - config.Set(coreconfig.OrgName, "") - config.Set(coreconfig.NodeDescription, "") - mim := nm.identity.(*identitymanagermocks.Manager) mim.On("GetMultipartyRootVerifier", nm.ctx, "ns1").Return(nil, fmt.Errorf("pop")) diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 552536e09a..7bcc447d7f 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -154,11 +154,20 @@ type IdentityPlugin struct { Config config.Section } +type MultipartyConfig struct { + Enabled bool + OrgName string + OrgDesc string + OrgKey string +} + type orchestrator struct { ctx context.Context cancelCtx context.CancelFunc started bool namespace string + defaultKey string + multiparty MultipartyConfig blockchain BlockchainPlugin identity identity.Manager idPlugin IdentityPlugin @@ -186,9 +195,11 @@ type orchestrator struct { txHelper txcommon.Helper } -func NewOrchestrator(ns string, bc BlockchainPlugin, db DatabasePlugin, ss SharedStoragePlugin, dx DataexchangePlugin, tokens map[string]TokensPlugin, id IdentityPlugin, metrics metrics.Manager) Orchestrator { +func NewOrchestrator(ns, defaultKey string, multiparty MultipartyConfig, bc BlockchainPlugin, db DatabasePlugin, ss SharedStoragePlugin, dx DataexchangePlugin, tokens map[string]TokensPlugin, id IdentityPlugin, metrics metrics.Manager) Orchestrator { or := &orchestrator{ namespace: ns, + defaultKey: defaultKey, + multiparty: multiparty, blockchain: bc, database: db, sharedstorage: ss, @@ -390,7 +401,7 @@ func (or *orchestrator) initComponents(ctx context.Context) (err error) { } if or.identity == nil { - or.identity, err = identity.NewIdentityManager(ctx, or.database.Plugin, or.idPlugin.Plugin, or.blockchain.Plugin, or.data) + or.identity, err = identity.NewIdentityManager(ctx, or.defaultKey, or.multiparty.OrgName, or.multiparty.OrgKey, or.database.Plugin, or.idPlugin.Plugin, or.blockchain.Plugin, or.data) if err != nil { return err } @@ -465,7 +476,7 @@ func (or *orchestrator) initComponents(ctx context.Context) (err error) { } if or.networkmap == nil { - or.networkmap, err = networkmap.NewNetworkMap(ctx, or.database.Plugin, or.broadcast, or.dataexchange.Plugin, or.identity, or.syncasync) + or.networkmap, err = networkmap.NewNetworkMap(ctx, or.multiparty.OrgName, or.multiparty.OrgDesc, or.database.Plugin, or.data, or.broadcast, or.dataexchange.Plugin, or.identity, or.syncasync) if err != nil { return err } diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index 9235d644a3..562e171165 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -169,6 +169,8 @@ func newTestOrchestrator() *testOrchestrator { func TestNewOrchestrator(t *testing.T) { or := NewOrchestrator( "ns1", + "0x1234", + MultipartyConfig{}, BlockchainPlugin{}, DatabasePlugin{}, SharedStoragePlugin{}, diff --git a/internal/orchestrator/status.go b/internal/orchestrator/status.go index 1baa3f0219..d36a233a4d 100644 --- a/internal/orchestrator/status.go +++ b/internal/orchestrator/status.go @@ -103,7 +103,7 @@ func (or *orchestrator) GetStatus(ctx context.Context, ns string) (status *core. Name: config.GetString(coreconfig.NodeName), }, Org: core.NodeStatusOrg{ - Name: or.namespace.GetMultipartyConfig(ns, coreconfig.OrgName), + Name: or.multiparty.OrgName, }, Plugins: or.getPlugins(), } diff --git a/internal/orchestrator/status_test.go b/internal/orchestrator/status_test.go index bf4779aaaa..9659d066c8 100644 --- a/internal/orchestrator/status_test.go +++ b/internal/orchestrator/status_test.go @@ -25,7 +25,6 @@ import ( "github.com/hyperledger/firefly/internal/coreconfig" "github.com/hyperledger/firefly/mocks/eventmocks" "github.com/hyperledger/firefly/mocks/identitymanagermocks" - "github.com/hyperledger/firefly/mocks/namespacemocks" "github.com/hyperledger/firefly/mocks/networkmapmocks" "github.com/hyperledger/firefly/pkg/core" "github.com/stretchr/testify/assert" @@ -113,8 +112,7 @@ func TestGetStatusRegistered(t *testing.T) { }}, }, nil, nil) - mns := or.namespace.(*namespacemocks.Manager) - mns.On("GetMultipartyConfig", "ns", coreconfig.OrgName).Return("org1") + or.multiparty.OrgName = "org1" mem := or.events.(*eventmocks.EventManager) mem.On("GetPlugins").Return(mockEventPlugins) @@ -177,9 +175,6 @@ func TestGetStatusVerifierLookupFail(t *testing.T) { mnm := or.networkmap.(*networkmapmocks.Manager) mnm.On("GetIdentityVerifiers", or.ctx, "ns", orgID.String(), mock.Anything).Return(nil, nil, fmt.Errorf("pop")) - mns := or.namespace.(*namespacemocks.Manager) - mns.On("GetMultipartyConfig", "ns", coreconfig.OrgName).Return("org1") - mem := or.events.(*eventmocks.EventManager) mem.On("GetPlugins").Return(mockEventPlugins) @@ -222,8 +217,7 @@ func TestGetStatusWrongNodeOwner(t *testing.T) { }}, }, nil, nil) - mns := or.namespace.(*namespacemocks.Manager) - mns.On("GetMultipartyConfig", "ns", coreconfig.OrgName).Return("org1") + or.multiparty.OrgName = "org1" mem := or.events.(*eventmocks.EventManager) mem.On("GetPlugins").Return(mockEventPlugins) @@ -254,8 +248,7 @@ func TestGetStatusUnregistered(t *testing.T) { mim := or.identity.(*identitymanagermocks.Manager) mim.On("GetMultipartyRootOrg", or.ctx, "ns").Return(nil, fmt.Errorf("pop")) - mns := or.namespace.(*namespacemocks.Manager) - mns.On("GetMultipartyConfig", "ns", coreconfig.OrgName).Return("org1") + or.multiparty.OrgName = "org1" mem := or.events.(*eventmocks.EventManager) mem.On("GetPlugins").Return(mockEventPlugins) @@ -302,8 +295,7 @@ func TestGetStatusOrgOnlyRegistered(t *testing.T) { }}, }, nil, nil) - mns := or.namespace.(*namespacemocks.Manager) - mns.On("GetMultipartyConfig", "ns", coreconfig.OrgName).Return("org1") + or.multiparty.OrgName = "org1" mem := or.events.(*eventmocks.EventManager) mem.On("GetPlugins").Return(mockEventPlugins) @@ -360,9 +352,6 @@ func TestGetStatusNodeError(t *testing.T) { }}, }, nil, nil) - mns := or.namespace.(*namespacemocks.Manager) - mns.On("GetMultipartyConfig", "ns", coreconfig.OrgName).Return("org1") - mem := or.events.(*eventmocks.EventManager) mem.On("GetPlugins").Return(mockEventPlugins) From a84363853bfc3e5170a8de0baceba72d0bb47283 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 3 Jun 2022 15:21:48 -0400 Subject: [PATCH 06/33] Fix startup issues Signed-off-by: Andrew Richardson --- internal/apiserver/server.go | 4 +- internal/identity/identitymanager.go | 7 +- internal/identity/identitymanager_test.go | 6 +- internal/metrics/metrics.go | 5 -- internal/metrics/metrics_test.go | 6 -- internal/namespace/manager.go | 85 ++++++++++++++-------- internal/orchestrator/orchestrator.go | 33 ++++----- internal/orchestrator/orchestrator_test.go | 1 + internal/orchestrator/status.go | 6 -- internal/orchestrator/status_test.go | 2 - mocks/namespacemocks/manager.go | 19 +++++ mocks/orchestratormocks/orchestrator.go | 18 ----- 12 files changed, 95 insertions(+), 97 deletions(-) diff --git a/internal/apiserver/server.go b/internal/apiserver/server.go index 6c0bdadf37..8877da72a8 100644 --- a/internal/apiserver/server.go +++ b/internal/apiserver/server.go @@ -231,7 +231,7 @@ func (as *apiServer) routeHandler(hf *ffapi.HandlerFactory, mgr namespace.Manage } } vars := mux.Vars(r.Req) - or := mgr.Orchestrator(vars["ns"]) + or := mgr.Orchestrator(extractNamespace(vars)) cr := &coreRequest{ or: or, ctx: r.Req.Context(), @@ -312,7 +312,7 @@ func (as *apiServer) notFoundHandler(res http.ResponseWriter, req *http.Request) func (as *apiServer) adminWSHandler(mgr namespace.Manager) http.HandlerFunc { // The admin events listener will be initialized when we start, so we access it it from Orchestrator on demand return func(w http.ResponseWriter, r *http.Request) { - // o.AdminEvents().ServeHTTPWebSocketListener(w, r) + mgr.AdminEvents().ServeHTTPWebSocketListener(w, r) } } diff --git a/internal/identity/identitymanager.go b/internal/identity/identitymanager.go index 5103bd40f9..1d4c2520a9 100644 --- a/internal/identity/identitymanager.go +++ b/internal/identity/identitymanager.go @@ -32,7 +32,6 @@ import ( "github.com/hyperledger/firefly/pkg/blockchain" "github.com/hyperledger/firefly/pkg/core" "github.com/hyperledger/firefly/pkg/database" - "github.com/hyperledger/firefly/pkg/identity" "github.com/karlseguin/ccache" ) @@ -57,7 +56,6 @@ type Manager interface { type identityManager struct { database database.Plugin - plugin identity.Plugin blockchain blockchain.Plugin data data.Manager @@ -72,13 +70,12 @@ type identityManager struct { signingKeyCache *ccache.Cache } -func NewIdentityManager(ctx context.Context, defaultKey, orgName, orgKey string, di database.Plugin, ii identity.Plugin, bi blockchain.Plugin, dm data.Manager) (Manager, error) { - if di == nil || ii == nil || bi == nil { +func NewIdentityManager(ctx context.Context, defaultKey, orgName, orgKey string, di database.Plugin, bi blockchain.Plugin, dm data.Manager) (Manager, error) { + if di == nil || bi == nil || dm == nil { return nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError, "IdentityManager") } im := &identityManager{ database: di, - plugin: ii, blockchain: bi, data: dm, defaultKey: defaultKey, diff --git a/internal/identity/identitymanager_test.go b/internal/identity/identitymanager_test.go index 06756bce28..eb46a35b88 100644 --- a/internal/identity/identitymanager_test.go +++ b/internal/identity/identitymanager_test.go @@ -26,7 +26,6 @@ import ( "github.com/hyperledger/firefly/mocks/blockchainmocks" "github.com/hyperledger/firefly/mocks/databasemocks" "github.com/hyperledger/firefly/mocks/datamocks" - "github.com/hyperledger/firefly/mocks/identitymocks" "github.com/hyperledger/firefly/pkg/core" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -36,20 +35,19 @@ func newTestIdentityManager(t *testing.T) (context.Context, *identityManager) { coreconfig.Reset() mdi := &databasemocks.Plugin{} - mii := &identitymocks.Plugin{} mbi := &blockchainmocks.Plugin{} mdm := &datamocks.Manager{} mbi.On("VerifierType").Return(core.VerifierTypeEthAddress).Maybe() ctx := context.Background() - im, err := NewIdentityManager(ctx, "", "", "", mdi, mii, mbi, mdm) + im, err := NewIdentityManager(ctx, "", "", "", mdi, mbi, mdm) assert.NoError(t, err) return ctx, im.(*identityManager) } func TestNewIdentityManagerMissingDeps(t *testing.T) { - _, err := NewIdentityManager(context.Background(), "", "", "", nil, nil, nil, nil) + _, err := NewIdentityManager(context.Background(), "", "", "", nil, nil, nil) assert.Regexp(t, "FF10128", err) } diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 98688e727e..ba56910872 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -42,7 +42,6 @@ type Manager interface { GetTime(id string) time.Time DeleteTime(id string) IsMetricsEnabled() bool - Start() error } type metricsManager struct { @@ -51,10 +50,6 @@ type metricsManager struct { timeMap map[string]time.Time } -func (mm *metricsManager) Start() error { - return nil -} - func NewMetricsManager(ctx context.Context) Manager { mm := &metricsManager{ ctx: ctx, diff --git a/internal/metrics/metrics_test.go b/internal/metrics/metrics_test.go index e2d2334f6b..19184c59a5 100644 --- a/internal/metrics/metrics_test.go +++ b/internal/metrics/metrics_test.go @@ -59,12 +59,6 @@ func newTestMetricsManager(t *testing.T) (*metricsManager, func()) { return mm, cancel } -func TestStartDoesNothing(t *testing.T) { - mm, cancel := newTestMetricsManager(t) - defer cancel() - assert.NoError(t, mm.Start()) -} - func TestCountBatchPin(t *testing.T) { mm, cancel := newTestMetricsManager(t) defer cancel() diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index 49e9ba6dd9..a7a98ef313 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -61,6 +61,7 @@ type Manager interface { WaitStop() Orchestrator(ns string) orchestrator.Orchestrator + AdminEvents() adminevents.Manager GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) } @@ -88,11 +89,15 @@ type namespaceManager struct { dataexchanges map[string]orchestrator.DataexchangePlugin tokens map[string]orchestrator.TokensPlugin adminEvents adminevents.Manager - namespaces map[string]namespace + namespaces map[string]*namespace + metricsEnabled bool } func NewNamespaceManager(withDefaults bool) Manager { - nm := &namespaceManager{} + nm := &namespaceManager{ + namespaces: make(map[string]*namespace), + metricsEnabled: config.GetBool(coreconfig.MetricsEnabled), + } InitConfig(withDefaults) @@ -128,7 +133,7 @@ func (nm *namespaceManager) Init(ctx context.Context, cancelCtx context.CancelFu // Start an orchestrator per namespace for name, ns := range nm.namespaces { - or := orchestrator.NewOrchestrator(name, ns.defaultKey, ns.multiparty, ns.blockchain, ns.database, ns.sharedstorage, ns.dataexchange, ns.tokens, ns.identity, nm.metrics) + or := orchestrator.NewOrchestrator(name, ns.defaultKey, ns.multiparty, ns.blockchain, ns.database, ns.sharedstorage, ns.dataexchange, ns.tokens, ns.identity, nm.metrics, nm.adminEvents) if err = or.Init(ctx, cancelCtx); err != nil { return err } @@ -138,6 +143,10 @@ func (nm *namespaceManager) Init(ctx context.Context, cancelCtx context.CancelFu } func (nm *namespaceManager) Start() error { + if nm.metricsEnabled { + // Ensure metrics are registered + metrics.Registry() + } for _, ns := range nm.namespaces { if err := ns.orchestrator.Start(); err != nil { return err @@ -150,11 +159,14 @@ func (nm *namespaceManager) WaitStop() { for _, ns := range nm.namespaces { ns.orchestrator.WaitStop() } + nm.adminEvents.WaitStop() } -func (nm *namespaceManager) getPlugins(ctx context.Context) (err error) { - //TODO: combine plugin/config section into a struct? to help w/ plugin initialization in orchestrator +func (nm *namespaceManager) AdminEvents() adminevents.Manager { + return nm.adminEvents +} +func (nm *namespaceManager) getPlugins(ctx context.Context) (err error) { nm.pluginNames = make(map[string]bool) if nm.metrics == nil { nm.metrics = metrics.NewMetricsManager(ctx) @@ -167,8 +179,6 @@ func (nm *namespaceManager) getPlugins(ctx context.Context) (err error) { } } - // Not really a plugin, but this has to be initialized here after the database (at least temporarily). - // Shortly after this step, namespaces will be synced to the database and will generate notifications to adminEvents. if nm.adminEvents == nil { nm.adminEvents = adminevents.NewAdminEventManager(ctx) } @@ -221,14 +231,15 @@ func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[s return nil, err } - plugin, err := tifactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) + pluginType := config.GetString(coreconfig.PluginConfigType) + plugin, err := tifactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } tokensPlugin := orchestrator.TokensPlugin{ Plugin: plugin, - Config: config, + Config: config.SubSection(pluginType), Name: config.GetString(coreconfig.PluginConfigName), } plugins[config.GetString(coreconfig.PluginConfigName)] = tokensPlugin @@ -279,14 +290,15 @@ func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map return nil, err } - plugin, err := difactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) + pluginType := config.GetString(coreconfig.PluginConfigType) + plugin, err := difactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } dbPlugin := orchestrator.DatabasePlugin{ Plugin: plugin, - Config: config, + Config: config.SubSection(pluginType), } plugins[config.GetString(coreconfig.PluginConfigName)] = dbPlugin @@ -294,6 +306,7 @@ func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map // check for deprecated config if len(nm.databases) == 0 { + pluginType := deprecatedDatabaseConfig.GetString(coreconfig.PluginConfigType) plugin, err := difactory.GetPlugin(ctx, deprecatedDatabaseConfig.GetString(coreconfig.PluginConfigType)) if err != nil { return nil, err @@ -301,7 +314,7 @@ func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map deprecatedPluginName := "database_0" dbPlugin := orchestrator.DatabasePlugin{ Plugin: plugin, - Config: deprecatedDatabaseConfig, + Config: deprecatedDatabaseConfig.SubSection(pluginType), } plugins[deprecatedPluginName] = dbPlugin @@ -338,13 +351,14 @@ func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins if err = nm.validatePluginConfig(ctx, config, "dataexchange"); err != nil { return nil, err } - plugin, err := dxfactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) + pluginType := config.GetString(coreconfig.PluginConfigType) + plugin, err := dxfactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } dxPlugin := orchestrator.DataexchangePlugin{ Plugin: plugin, - Config: config, + Config: config.SubSection(pluginType), } plugins[config.GetString(coreconfig.PluginConfigName)] = dxPlugin @@ -353,15 +367,15 @@ func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins if len(plugins) == 0 { log.L(ctx).Warnf("Your data exchange config uses a deprecated configuration structure - the data exchange configuration has been moved under the 'plugins' section") deprecatedPluginName := "dataexchange_0" - dxType := deprecatedDataexchangeConfig.GetString(coreconfig.PluginConfigType) - plugin, err := dxfactory.GetPlugin(ctx, dxType) + pluginType := deprecatedDataexchangeConfig.GetString(coreconfig.PluginConfigType) + plugin, err := dxfactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } dxPlugin := orchestrator.DataexchangePlugin{ Plugin: plugin, - Config: deprecatedDataexchangeConfig, + Config: deprecatedDataexchangeConfig.SubSection(pluginType), } plugins[deprecatedPluginName] = dxPlugin @@ -378,14 +392,15 @@ func (nm *namespaceManager) getIdentityPlugins(ctx context.Context) (plugins map if err = nm.validatePluginConfig(ctx, config, "identity"); err != nil { return nil, err } - plugin, err := iifactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) + pluginType := config.GetString(coreconfig.PluginConfigType) + plugin, err := iifactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } idPlugin := orchestrator.IdentityPlugin{ Plugin: plugin, - Config: config, + Config: config.SubSection(pluginType), } plugins[config.GetString(coreconfig.PluginConfigName)] = idPlugin } @@ -402,30 +417,31 @@ func (nm *namespaceManager) getBlockchainPlugins(ctx context.Context) (plugins m return nil, err } - plugin, err := bifactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) + pluginType := config.GetString(coreconfig.PluginConfigType) + plugin, err := bifactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } bcPlugin := orchestrator.BlockchainPlugin{ Plugin: plugin, - Config: config, + Config: config.SubSection(pluginType), } plugins[config.GetString(coreconfig.PluginConfigName)] = bcPlugin } // check deprecated config if len(plugins) == 0 { - deprecatedPluginName := "database_0" - biType := deprecatedBlockchainConfig.GetString(coreconfig.PluginConfigType) - plugin, err := bifactory.GetPlugin(ctx, biType) + deprecatedPluginName := "blockchain_0" + pluginType := deprecatedBlockchainConfig.GetString(coreconfig.PluginConfigType) + plugin, err := bifactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } bcPlugin := orchestrator.BlockchainPlugin{ Plugin: plugin, - Config: deprecatedBlockchainConfig, + Config: deprecatedBlockchainConfig.SubSection(pluginType), } plugins[deprecatedPluginName] = bcPlugin } @@ -441,14 +457,15 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin if err = nm.validatePluginConfig(ctx, config, "sharedstorage"); err != nil { return nil, err } - plugin, err := ssfactory.GetPlugin(ctx, config.GetString(coreconfig.PluginConfigType)) + pluginType := config.GetString(coreconfig.PluginConfigType) + plugin, err := ssfactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } ssPlugin := orchestrator.SharedStoragePlugin{ Plugin: plugin, - Config: config, + Config: config.SubSection(pluginType), } plugins[config.GetString(coreconfig.PluginConfigName)] = ssPlugin } @@ -456,15 +473,15 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin // check deprecated config if len(plugins) == 0 { deprecatedPluginName := "sharedstorage_0" - ssType := deprecatedSharedStorageConfig.GetString(coreconfig.PluginConfigType) - plugin, err := ssfactory.GetPlugin(ctx, ssType) + pluginType := deprecatedSharedStorageConfig.GetString(coreconfig.PluginConfigType) + plugin, err := ssfactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } ssPlugin := orchestrator.SharedStoragePlugin{ Plugin: plugin, - Config: deprecatedSharedStorageConfig, + Config: deprecatedSharedStorageConfig.SubSection(pluginType), } plugins[deprecatedPluginName] = ssPlugin } @@ -551,6 +568,10 @@ func (nm *namespaceManager) buildAndValidateNamespaces(ctx context.Context, name for plugin := range nm.databases { plugins = append(plugins, plugin) } + + for plugin := range nm.tokens { + plugins = append(plugins, plugin) + } } defaultKey := conf.GetString(coreconfig.NamespaceDefaultKey) @@ -573,7 +594,7 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name, var dxPlugin bool var bcPlugin bool - ns := namespace{ + ns := &namespace{ tokens: make(map[string]orchestrator.TokensPlugin), multiparty: config, defaultKey: defaultKey, @@ -636,7 +657,7 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name, def var dbPlugin bool var bcPlugin bool - ns := namespace{ + ns := &namespace{ tokens: make(map[string]orchestrator.TokensPlugin), defaultKey: defaultKey, } diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 7bcc447d7f..e15848eac7 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -54,7 +54,6 @@ type Orchestrator interface { Init(ctx context.Context, cancelCtx context.CancelFunc) error Start() error WaitStop() // The close itself is performed by canceling the context - AdminEvents() adminevents.Manager Assets() assets.Manager BatchManager() batch.Manager Broadcast() broadcast.Manager @@ -190,12 +189,12 @@ type orchestrator struct { node *fftypes.UUID metrics metrics.Manager operations operations.Manager - adminEvents adminevents.Manager sharedDownload shareddownload.Manager txHelper txcommon.Helper + adminEvents adminevents.Manager } -func NewOrchestrator(ns, defaultKey string, multiparty MultipartyConfig, bc BlockchainPlugin, db DatabasePlugin, ss SharedStoragePlugin, dx DataexchangePlugin, tokens map[string]TokensPlugin, id IdentityPlugin, metrics metrics.Manager) Orchestrator { +func NewOrchestrator(ns, defaultKey string, multiparty MultipartyConfig, bc BlockchainPlugin, db DatabasePlugin, ss SharedStoragePlugin, dx DataexchangePlugin, tokens map[string]TokensPlugin, id IdentityPlugin, metrics metrics.Manager, adminEvents adminevents.Manager) Orchestrator { or := &orchestrator{ namespace: ns, defaultKey: defaultKey, @@ -207,6 +206,7 @@ func NewOrchestrator(ns, defaultKey string, multiparty MultipartyConfig, bc Bloc tokens: tokens, idPlugin: id, metrics: metrics, + adminEvents: adminEvents, } return or @@ -230,11 +230,14 @@ func (or *orchestrator) Init(ctx context.Context, cancelCtx context.CancelFunc) func (or *orchestrator) Start() (err error) { var ns *core.Namespace - err = or.metrics.Start() - if err == nil { - ns, err = or.database.Plugin.GetNamespace(or.ctx, or.namespace) - } + ns, err = or.database.Plugin.GetNamespace(or.ctx, or.namespace) if err == nil { + if ns == nil { + ns = &core.Namespace{ + Name: or.namespace, + Created: fftypes.Now(), + } + } err = or.blockchain.Plugin.ConfigureContract(or.ctx, &ns.Contracts) } if err == nil { @@ -296,10 +299,6 @@ func (or *orchestrator) WaitStop() { or.operations.WaitStop() or.operations = nil } - if or.adminEvents != nil { - or.adminEvents.WaitStop() - or.adminEvents = nil - } or.started = false } @@ -343,10 +342,6 @@ func (or *orchestrator) Operations() operations.Manager { return or.operations } -func (or *orchestrator) AdminEvents() adminevents.Manager { - return or.adminEvents -} - func (or *orchestrator) initPlugins(ctx context.Context) (err error) { err = or.database.Plugin.Init(ctx, or.database.Config, or) if err != nil { @@ -401,7 +396,7 @@ func (or *orchestrator) initComponents(ctx context.Context) (err error) { } if or.identity == nil { - or.identity, err = identity.NewIdentityManager(ctx, or.defaultKey, or.multiparty.OrgName, or.multiparty.OrgKey, or.database.Plugin, or.idPlugin.Plugin, or.blockchain.Plugin, or.data) + or.identity, err = identity.NewIdentityManager(ctx, or.defaultKey, or.multiparty.OrgName, or.multiparty.OrgKey, or.database.Plugin, or.blockchain.Plugin, or.data) if err != nil { return err } @@ -441,7 +436,11 @@ func (or *orchestrator) initComponents(ctx context.Context) (err error) { } if or.assets == nil { - or.assets, err = assets.NewAssetManager(ctx, or.database.Plugin, or.identity, or.data, or.syncasync, or.broadcast, or.messaging, nil, or.metrics, or.operations, or.txHelper) + plugins := make(map[string]tokens.Plugin, len(or.tokens)) + for _, v := range or.tokens { + plugins[v.Name] = v.Plugin + } + or.assets, err = assets.NewAssetManager(ctx, or.database.Plugin, or.identity, or.data, or.syncasync, or.broadcast, or.messaging, plugins, or.metrics, or.operations, or.txHelper) if err != nil { return err } diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index 562e171165..fd018e2412 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -178,6 +178,7 @@ func TestNewOrchestrator(t *testing.T) { map[string]TokensPlugin{}, IdentityPlugin{}, &metricsmocks.Manager{}, + &admineventsmocks.Manager{}, ) assert.NotNil(t, or) } diff --git a/internal/orchestrator/status.go b/internal/orchestrator/status.go index d36a233a4d..263f5a4a11 100644 --- a/internal/orchestrator/status.go +++ b/internal/orchestrator/status.go @@ -58,18 +58,12 @@ func (or *orchestrator) getPlugins() core.NodeStatusPlugins { PluginType: or.dataexchange.Plugin.Name(), }) - identityPluginArray := make([]*core.NodeStatusPlugin, 0) - identityPluginArray = append(identityPluginArray, &core.NodeStatusPlugin{ - PluginType: or.idPlugin.Plugin.Name(), - }) - return core.NodeStatusPlugins{ Blockchain: blockchainsArray, Database: databasesArray, SharedStorage: sharedstorageArray, DataExchange: dataexchangeArray, Events: or.events.GetPlugins(), - Identity: identityPluginArray, Tokens: tokensArray, } } diff --git a/internal/orchestrator/status_test.go b/internal/orchestrator/status_test.go index 9659d066c8..361bf1a540 100644 --- a/internal/orchestrator/status_test.go +++ b/internal/orchestrator/status_test.go @@ -137,7 +137,6 @@ func TestGetStatusRegistered(t *testing.T) { assert.ElementsMatch(t, pluginsResult.Database, status.Plugins.Database) assert.ElementsMatch(t, pluginsResult.DataExchange, status.Plugins.DataExchange) assert.ElementsMatch(t, pluginsResult.Events, status.Plugins.Events) - assert.ElementsMatch(t, pluginsResult.Identity, status.Plugins.Identity) assert.ElementsMatch(t, pluginsResult.SharedStorage, status.Plugins.SharedStorage) assert.ElementsMatch(t, pluginsResult.Tokens, status.Plugins.Tokens) @@ -318,7 +317,6 @@ func TestGetStatusOrgOnlyRegistered(t *testing.T) { assert.ElementsMatch(t, pluginsResult.Database, status.Plugins.Database) assert.ElementsMatch(t, pluginsResult.DataExchange, status.Plugins.DataExchange) assert.ElementsMatch(t, pluginsResult.Events, status.Plugins.Events) - assert.ElementsMatch(t, pluginsResult.Identity, status.Plugins.Identity) assert.ElementsMatch(t, pluginsResult.SharedStorage, status.Plugins.SharedStorage) assert.ElementsMatch(t, pluginsResult.Tokens, status.Plugins.Tokens) diff --git a/mocks/namespacemocks/manager.go b/mocks/namespacemocks/manager.go index efe83c99eb..392666706b 100644 --- a/mocks/namespacemocks/manager.go +++ b/mocks/namespacemocks/manager.go @@ -5,7 +5,10 @@ package namespacemocks import ( context "context" + adminevents "github.com/hyperledger/firefly/internal/adminevents" + core "github.com/hyperledger/firefly/pkg/core" + database "github.com/hyperledger/firefly/pkg/database" mock "github.com/stretchr/testify/mock" @@ -18,6 +21,22 @@ type Manager struct { mock.Mock } +// AdminEvents provides a mock function with given fields: +func (_m *Manager) AdminEvents() adminevents.Manager { + ret := _m.Called() + + var r0 adminevents.Manager + if rf, ok := ret.Get(0).(func() adminevents.Manager); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(adminevents.Manager) + } + } + + return r0 +} + // GetNamespaces provides a mock function with given fields: ctx, filter func (_m *Manager) GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) { ret := _m.Called(ctx, filter) diff --git a/mocks/orchestratormocks/orchestrator.go b/mocks/orchestratormocks/orchestrator.go index 3585e04cdd..fc50d67e39 100644 --- a/mocks/orchestratormocks/orchestrator.go +++ b/mocks/orchestratormocks/orchestrator.go @@ -3,9 +3,7 @@ package orchestratormocks import ( - adminevents "github.com/hyperledger/firefly/internal/adminevents" assets "github.com/hyperledger/firefly/internal/assets" - batch "github.com/hyperledger/firefly/internal/batch" broadcast "github.com/hyperledger/firefly/internal/broadcast" @@ -38,22 +36,6 @@ type Orchestrator struct { mock.Mock } -// AdminEvents provides a mock function with given fields: -func (_m *Orchestrator) AdminEvents() adminevents.Manager { - ret := _m.Called() - - var r0 adminevents.Manager - if rf, ok := ret.Get(0).(func() adminevents.Manager); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(adminevents.Manager) - } - } - - return r0 -} - // Assets provides a mock function with given fields: func (_m *Orchestrator) Assets() assets.Manager { ret := _m.Called() From 5aaccaad2a184aed25ae123affabb4da32b489b9 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 3 Jun 2022 15:51:03 -0400 Subject: [PATCH 07/33] Bring back /pins route Move this out of /status (since it's just a collection query), and put it under namespaces like most of the other routes. Signed-off-by: Andrew Richardson --- docs/swagger/swagger.yaml | 291 ++++++++++++++++++++++ internal/apiserver/route_get_pins.go | 44 ++++ internal/apiserver/route_get_pins_test.go | 39 +++ internal/apiserver/routes.go | 1 + 4 files changed, 375 insertions(+) create mode 100644 internal/apiserver/route_get_pins.go create mode 100644 internal/apiserver/route_get_pins_test.go diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 6cf475aeca..50686b3070 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -19490,6 +19490,155 @@ paths: description: "" tags: - Non-Default Namespace + /namespaces/{ns}/pins: + get: + description: Queries the pins table that is the status of the event aggregator + operationId: getPinsNamespace + parameters: + - description: The namespace which scopes this request + in: path + name: ns + required: true + schema: + example: default + type: string + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: batch + 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: dispatched + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: hash + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: index + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: masked + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: sequence + 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: + batch: + description: The UUID of the batch of messages this pin is part + of + format: uuid + type: string + batchHash: + description: The manifest hash batch of messages this pin is + part of + format: byte + type: string + created: + description: The time the FireFly node created the pin + format: date-time + type: string + dispatched: + description: Once true, this pin has been processed and will + not be processed again + type: boolean + hash: + description: The hash represents a topic within a message in + the batch. If a message has multiple topics, then multiple + pins are created. If the message is private, the hash is masked + for privacy + format: byte + type: string + index: + description: The index of this pin within the batch. One pin + is created for each topic, of each message in the batch + format: int64 + type: integer + masked: + description: True if the pin is for a private message, and hence + is masked with the group ID and salted with a nonce so observers + of the blockchain cannot use pin hash to match this transaction + to other transactions or participants + type: boolean + sequence: + description: The order of the pin in the local FireFly database, + which matches the order in which pins were delivered to FireFly + by the blockchain connector event stream + format: int64 + type: integer + signer: + description: The blockchain signing key that submitted this + transaction, as passed through to FireFly by the smart contract + that emitted the blockchain event + type: string + type: object + type: array + description: Success + default: + description: "" + tags: + - Non-Default Namespace /namespaces/{ns}/status: get: description: Gets the status of this node @@ -26740,6 +26889,148 @@ paths: description: "" tags: - Default Namespace + /pins: + get: + description: Queries the pins table that is the status of the event aggregator + operationId: getPins + parameters: + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: batch + 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: dispatched + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: hash + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: index + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: masked + schema: + type: string + - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' + in: query + name: sequence + 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: + batch: + description: The UUID of the batch of messages this pin is part + of + format: uuid + type: string + batchHash: + description: The manifest hash batch of messages this pin is + part of + format: byte + type: string + created: + description: The time the FireFly node created the pin + format: date-time + type: string + dispatched: + description: Once true, this pin has been processed and will + not be processed again + type: boolean + hash: + description: The hash represents a topic within a message in + the batch. If a message has multiple topics, then multiple + pins are created. If the message is private, the hash is masked + for privacy + format: byte + type: string + index: + description: The index of this pin within the batch. One pin + is created for each topic, of each message in the batch + format: int64 + type: integer + masked: + description: True if the pin is for a private message, and hence + is masked with the group ID and salted with a nonce so observers + of the blockchain cannot use pin hash to match this transaction + to other transactions or participants + type: boolean + sequence: + description: The order of the pin in the local FireFly database, + which matches the order in which pins were delivered to FireFly + by the blockchain connector event stream + format: int64 + type: integer + signer: + description: The blockchain signing key that submitted this + transaction, as passed through to FireFly by the smart contract + that emitted the blockchain event + type: string + type: object + type: array + description: Success + default: + description: "" + tags: + - Default Namespace /status: get: description: Gets the status of this node diff --git a/internal/apiserver/route_get_pins.go b/internal/apiserver/route_get_pins.go new file mode 100644 index 0000000000..d45a0500db --- /dev/null +++ b/internal/apiserver/route_get_pins.go @@ -0,0 +1,44 @@ +// Copyright © 2022 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-common/pkg/ffapi" + "github.com/hyperledger/firefly/internal/coremsgs" + "github.com/hyperledger/firefly/pkg/core" + "github.com/hyperledger/firefly/pkg/database" +) + +var getPins = &ffapi.Route{ + Name: "getPins", + Path: "pins", + Method: http.MethodGet, + PathParams: nil, + QueryParams: nil, + Description: coremsgs.APIEndpointsGetStatusPins, + JSONInputValue: nil, + JSONOutputValue: func() interface{} { return []core.Pin{} }, + JSONOutputCodes: []int{http.StatusOK}, + Extensions: &coreExtensions{ + FilterFactory: database.PinQueryFactory, + CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { + return filterResult(cr.or.GetPins(cr.ctx, cr.filter)) + }, + }, +} diff --git a/internal/apiserver/route_get_pins_test.go b/internal/apiserver/route_get_pins_test.go new file mode 100644 index 0000000000..4bcf052288 --- /dev/null +++ b/internal/apiserver/route_get_pins_test.go @@ -0,0 +1,39 @@ +// 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/pkg/core" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestGetPins(t *testing.T) { + o, r := newTestAPIServer() + req := httptest.NewRequest("GET", "/api/v1/pins", nil) + req.Header.Set("Content-Type", "application/json; charset=utf-8") + res := httptest.NewRecorder() + + o.On("GetPins", mock.Anything, mock.Anything). + Return([]*core.Pin{}, nil, nil) + r.ServeHTTP(res, req) + + assert.Equal(t, 200, res.Result().StatusCode) +} diff --git a/internal/apiserver/routes.go b/internal/apiserver/routes.go index 2eddad75ac..95c44bc768 100644 --- a/internal/apiserver/routes.go +++ b/internal/apiserver/routes.go @@ -91,6 +91,7 @@ var routes = append( getNetworkOrgs, getOpByID, getOps, + getPins, getStatus, getSubscriptionByID, getSubscriptions, From 865b9196f8b596a8a04abd0ef81cf840b36da0d5 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 3 Jun 2022 16:00:32 -0400 Subject: [PATCH 08/33] Add mutex around prometheus singletons Avoid setting these twice. Signed-off-by: Andrew Richardson --- internal/metrics/prometheus.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/internal/metrics/prometheus.go b/internal/metrics/prometheus.go index 5bb7047e1c..7d391179c7 100644 --- a/internal/metrics/prometheus.go +++ b/internal/metrics/prometheus.go @@ -17,17 +17,23 @@ package metrics import ( + "sync" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" muxprom "gitlab.com/hfuss/mux-prometheus/pkg/middleware" ) +var registryMux sync.Mutex var registry *prometheus.Registry +var instrumentationMux sync.Mutex var adminInstrumentation *muxprom.Instrumentation var restInstrumentation *muxprom.Instrumentation // Registry returns FireFly's customized Prometheus registry func Registry() *prometheus.Registry { + registryMux.Lock() + defer registryMux.Unlock() if registry == nil { initMetricsCollectors() registry = prometheus.NewRegistry() @@ -40,6 +46,8 @@ func Registry() *prometheus.Registry { // GetAdminServerInstrumentation returns the admin server's Prometheus middleware, ensuring its metrics are never // registered twice func GetAdminServerInstrumentation() *muxprom.Instrumentation { + instrumentationMux.Lock() + defer instrumentationMux.Unlock() if adminInstrumentation == nil { adminInstrumentation = NewInstrumentation("admin") } @@ -49,6 +57,8 @@ func GetAdminServerInstrumentation() *muxprom.Instrumentation { // GetRestServerInstrumentation returns the REST server's Prometheus middleware, ensuring its metrics are never // registered twice func GetRestServerInstrumentation() *muxprom.Instrumentation { + instrumentationMux.Lock() + defer instrumentationMux.Unlock() if restInstrumentation == nil { restInstrumentation = NewInstrumentation("rest") } From 2678910fe97f28076d089126212ccc7f7e2b0761 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 3 Jun 2022 16:03:54 -0400 Subject: [PATCH 09/33] Add back /status/batchmanager route Now under /namespaces. Signed-off-by: Andrew Richardson --- docs/swagger/swagger.yaml | 191 ++++++++++++++++++ .../route_get_status_batchmanager.go | 43 ++++ .../route_get_status_batchmanager_test.go | 42 ++++ internal/apiserver/routes.go | 1 + 4 files changed, 277 insertions(+) create mode 100644 internal/apiserver/route_get_status_batchmanager.go create mode 100644 internal/apiserver/route_get_status_batchmanager_test.go diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 50686b3070..13e2174001 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -19823,6 +19823,105 @@ paths: description: "" tags: - Non-Default Namespace + /namespaces/{ns}/status/batchmanager: + get: + description: Gets the status of the batch manager + operationId: getStatusBatchManagerNamespace + parameters: + - description: The namespace which scopes this request + in: path + name: ns + required: true + schema: + example: default + type: string + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + responses: + "200": + content: + application/json: + schema: + properties: + processors: + description: An array of currently active batch processors + items: + description: An array of currently active batch processors + properties: + dispatcher: + description: The type of dispatcher for this processor + type: string + name: + description: The name of the processor, which includes details + of the attributes of message are allocated to this processor + type: string + status: + description: The flush status for this batch processor + properties: + averageBatchBytes: + description: The average byte size of each batch + format: int64 + type: integer + averageBatchData: + description: The average number of data attachments + included in each batch + format: double + type: number + averageBatchMessages: + description: The average number of messages included + in each batch + format: double + type: number + averageFlushTimeMS: + description: The average amount of time spent flushing + each batch + format: int64 + type: integer + blocked: + description: True if the batch flush is in a retry loop, + due to errors being returned by the plugins + type: boolean + flushing: + description: If a flush is in progress, this is the + UUID of the batch being flushed + format: uuid + type: string + lastFlushError: + description: The last error received by this batch processor + while flushing + type: string + lastFlushErrorTime: + description: The time of the last flush + format: date-time + type: string + lastFlushStartTime: + description: The last time a flush was performed + format: date-time + type: string + totalBatches: + description: The total count of batches flushed by this + processor since it started + format: int64 + type: integer + totalErrors: + description: The total count of error flushed encountered + by this processor since it started + format: int64 + type: integer + type: object + type: object + type: array + type: object + description: Success + default: + description: "" + tags: + - Non-Default Namespace /namespaces/{ns}/subscriptions: get: description: Gets a list of subscriptions @@ -27208,6 +27307,98 @@ paths: description: "" tags: - Default Namespace + /status/batchmanager: + get: + description: Gets the status of the batch manager + operationId: getStatusBatchManager + parameters: + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + responses: + "200": + content: + application/json: + schema: + properties: + processors: + description: An array of currently active batch processors + items: + description: An array of currently active batch processors + properties: + dispatcher: + description: The type of dispatcher for this processor + type: string + name: + description: The name of the processor, which includes details + of the attributes of message are allocated to this processor + type: string + status: + description: The flush status for this batch processor + properties: + averageBatchBytes: + description: The average byte size of each batch + format: int64 + type: integer + averageBatchData: + description: The average number of data attachments + included in each batch + format: double + type: number + averageBatchMessages: + description: The average number of messages included + in each batch + format: double + type: number + averageFlushTimeMS: + description: The average amount of time spent flushing + each batch + format: int64 + type: integer + blocked: + description: True if the batch flush is in a retry loop, + due to errors being returned by the plugins + type: boolean + flushing: + description: If a flush is in progress, this is the + UUID of the batch being flushed + format: uuid + type: string + lastFlushError: + description: The last error received by this batch processor + while flushing + type: string + lastFlushErrorTime: + description: The time of the last flush + format: date-time + type: string + lastFlushStartTime: + description: The last time a flush was performed + format: date-time + type: string + totalBatches: + description: The total count of batches flushed by this + processor since it started + format: int64 + type: integer + totalErrors: + description: The total count of error flushed encountered + by this processor since it started + format: int64 + type: integer + type: object + type: object + type: array + type: object + description: Success + default: + description: "" + tags: + - Default Namespace /subscriptions: get: description: Gets a list of subscriptions diff --git a/internal/apiserver/route_get_status_batchmanager.go b/internal/apiserver/route_get_status_batchmanager.go new file mode 100644 index 0000000000..50979fed28 --- /dev/null +++ b/internal/apiserver/route_get_status_batchmanager.go @@ -0,0 +1,43 @@ +// Copyright © 2022 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-common/pkg/ffapi" + "github.com/hyperledger/firefly/internal/batch" + "github.com/hyperledger/firefly/internal/coremsgs" +) + +var getStatusBatchManager = &ffapi.Route{ + Name: "getStatusBatchManager", + Path: "status/batchmanager", + Method: http.MethodGet, + PathParams: nil, + QueryParams: nil, + Description: coremsgs.APIEndpointsGetStatusBatchManager, + JSONInputValue: nil, + JSONOutputValue: func() interface{} { return &batch.ManagerStatus{} }, + JSONOutputCodes: []int{http.StatusOK}, + Extensions: &coreExtensions{ + CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { + output = cr.or.BatchManager().Status() + return output, nil + }, + }, +} diff --git a/internal/apiserver/route_get_status_batchmanager_test.go b/internal/apiserver/route_get_status_batchmanager_test.go new file mode 100644 index 0000000000..07380af68c --- /dev/null +++ b/internal/apiserver/route_get_status_batchmanager_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/internal/batch" + "github.com/hyperledger/firefly/mocks/batchmocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestGetStatusBatching(t *testing.T) { + o, r := newTestAPIServer() + req := httptest.NewRequest("GET", "/api/v1/status/batchmanager", nil) + req.Header.Set("Content-Type", "application/json; charset=utf-8") + res := httptest.NewRecorder() + + mbm := &batchmocks.Manager{} + o.On("BatchManager").Return(mbm) + mbm.On("Status", mock.Anything, mock.Anything). + Return(&batch.ManagerStatus{}, nil) + r.ServeHTTP(res, req) + + assert.Equal(t, 200, res.Result().StatusCode) +} diff --git a/internal/apiserver/routes.go b/internal/apiserver/routes.go index 95c44bc768..495e78cc7a 100644 --- a/internal/apiserver/routes.go +++ b/internal/apiserver/routes.go @@ -93,6 +93,7 @@ var routes = append( getOps, getPins, getStatus, + getStatusBatchManager, getSubscriptionByID, getSubscriptions, getTokenAccountPools, From 6c01acb9a79509238bdcdcda394e65b96b622820 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Fri, 3 Jun 2022 16:28:31 -0400 Subject: [PATCH 10/33] Bring back /websockets route Remove the "/status" prefix, since this is a global route and no longer grouped with the other "status" routes. Signed-off-by: Andrew Richardson --- docs/swagger/swagger.yaml | 65 +++++++++++++++++++ internal/apiserver/route_get_websockets.go | 45 +++++++++++++ .../apiserver/route_get_websockets_test.go | 40 ++++++++++++ internal/apiserver/routes.go | 1 + internal/events/event_manager.go | 5 -- internal/events/event_manager_test.go | 13 ---- internal/events/subscription_manager.go | 9 --- 7 files changed, 151 insertions(+), 27 deletions(-) create mode 100644 internal/apiserver/route_get_websockets.go create mode 100644 internal/apiserver/route_get_websockets_test.go diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 13e2174001..08fa3a3bd8 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -32300,5 +32300,70 @@ paths: description: "" tags: - Default Namespace + /websockets: + get: + description: Gets the status of the current WebSocket connections to this node + operationId: getWebSockets + parameters: + - description: Server-side request timeout (milliseconds, or set a custom suffix + like 10s) + in: header + name: Request-Timeout + schema: + default: 2m0s + type: string + responses: + "200": + content: + application/json: + schema: + properties: + connections: + description: List of currently active websocket client connections + items: + description: List of currently active websocket client connections + properties: + id: + description: The unique ID assigned to this client connection + type: string + remoteAddress: + description: The remote address of the connected client + (if available) + type: string + subscriptions: + description: List of subscriptions currently started by + this client + items: + description: List of subscriptions currently started by + this client + properties: + ephemeral: + description: Indicates whether the subscription is + ephemeral (vs durable) + type: boolean + name: + description: The subscription name (for durable subscriptions + only) + type: string + namespace: + description: The subscription namespace + type: string + type: object + type: array + userAgent: + description: The user agent of the connected client (if + available) + type: string + type: object + type: array + enabled: + description: Indicates whether the websockets plugin is enabled + type: boolean + type: object + description: Success + default: + description: "" + tags: + - Global servers: - url: http://localhost:5000 diff --git a/internal/apiserver/route_get_websockets.go b/internal/apiserver/route_get_websockets.go new file mode 100644 index 0000000000..542dff34af --- /dev/null +++ b/internal/apiserver/route_get_websockets.go @@ -0,0 +1,45 @@ +// Copyright © 2022 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-common/pkg/ffapi" + "github.com/hyperledger/firefly/internal/coremsgs" + "github.com/hyperledger/firefly/internal/events/eifactory" + "github.com/hyperledger/firefly/internal/events/websockets" + "github.com/hyperledger/firefly/pkg/core" +) + +var getWebSockets = &ffapi.Route{ + Name: "getWebSockets", + Path: "websockets", + Method: http.MethodGet, + PathParams: nil, + QueryParams: nil, + Description: coremsgs.APIEndpointsGetStatusWebSockets, + JSONInputValue: nil, + JSONOutputValue: func() interface{} { return &core.WebSocketStatus{} }, + JSONOutputCodes: []int{http.StatusOK}, + Extensions: &coreExtensions{ + CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { + ws, _ := eifactory.GetPlugin(cr.ctx, "websockets") + return ws.(*websockets.WebSockets).GetStatus(), nil + }, + }, +} diff --git a/internal/apiserver/route_get_websockets_test.go b/internal/apiserver/route_get_websockets_test.go new file mode 100644 index 0000000000..183f37416d --- /dev/null +++ b/internal/apiserver/route_get_websockets_test.go @@ -0,0 +1,40 @@ +// 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/eventmocks" + "github.com/hyperledger/firefly/pkg/core" + "github.com/stretchr/testify/assert" +) + +func TestGetWebSockets(t *testing.T) { + o, r := newTestAPIServer() + mem := &eventmocks.EventManager{} + o.On("Events").Return(mem) + req := httptest.NewRequest("GET", "/api/v1/websockets", nil) + req.Header.Set("Content-Type", "application/json; charset=utf-8") + res := httptest.NewRecorder() + + mem.On("GetWebSocketStatus").Return(&core.WebSocketStatus{}) + r.ServeHTTP(res, req) + + assert.Equal(t, 200, res.Result().StatusCode) +} diff --git a/internal/apiserver/routes.go b/internal/apiserver/routes.go index 495e78cc7a..856764e8ff 100644 --- a/internal/apiserver/routes.go +++ b/internal/apiserver/routes.go @@ -44,6 +44,7 @@ var routes = append( globalRoutes([]*ffapi.Route{ getNamespace, getNamespaces, + getWebSockets, }), namespacedRoutes([]*ffapi.Route{ deleteContractListener, diff --git a/internal/events/event_manager.go b/internal/events/event_manager.go index 300dec4b08..4e0107dc2b 100644 --- a/internal/events/event_manager.go +++ b/internal/events/event_manager.go @@ -59,7 +59,6 @@ type EventManager interface { DeletedSubscriptions() chan<- *fftypes.UUID DeleteDurableSubscription(ctx context.Context, subDef *core.Subscription) (err error) CreateUpdateDurableSubscription(ctx context.Context, subDef *core.Subscription, mustNew bool) (err error) - GetWebSocketStatus() *core.WebSocketStatus Start() error WaitStop() @@ -259,7 +258,3 @@ func (em *eventManager) GetPlugins() []*core.NodeStatusPlugin { return eventsArray } - -func (em *eventManager) GetWebSocketStatus() *core.WebSocketStatus { - return em.subManager.getWebSocketStatus() -} diff --git a/internal/events/event_manager_test.go b/internal/events/event_manager_test.go index 655c0ffa40..6ce2ee73df 100644 --- a/internal/events/event_manager_test.go +++ b/internal/events/event_manager_test.go @@ -42,7 +42,6 @@ import ( "github.com/hyperledger/firefly/mocks/txcommonmocks" "github.com/hyperledger/firefly/pkg/core" "github.com/hyperledger/firefly/pkg/database" - "github.com/hyperledger/firefly/pkg/events" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -425,15 +424,3 @@ func TestGetPlugins(t *testing.T) { assert.ElementsMatch(t, em.GetPlugins(), expectedPlugins) } - -func TestGetWebSocketStatus(t *testing.T) { - em, cancel := newTestEventManager(t) - defer cancel() - - status := em.GetWebSocketStatus() - assert.Equal(t, true, status.Enabled) - - em.subManager.transports = make(map[string]events.Plugin) - status = em.GetWebSocketStatus() - assert.Equal(t, false, status.Enabled) -} diff --git a/internal/events/subscription_manager.go b/internal/events/subscription_manager.go index b141bc2dfc..07860ed9cd 100644 --- a/internal/events/subscription_manager.go +++ b/internal/events/subscription_manager.go @@ -32,7 +32,6 @@ import ( "github.com/hyperledger/firefly/internal/data" "github.com/hyperledger/firefly/internal/events/eifactory" "github.com/hyperledger/firefly/internal/events/system" - "github.com/hyperledger/firefly/internal/events/websockets" "github.com/hyperledger/firefly/internal/privatemessaging" "github.com/hyperledger/firefly/internal/txcommon" "github.com/hyperledger/firefly/pkg/core" @@ -570,11 +569,3 @@ func (sm *subscriptionManager) deliveryResponse(ei events.Plugin, connID string, sm.mux.Unlock() dispatcher.deliveryResponse(inflight) } - -func (sm *subscriptionManager) getWebSocketStatus() *core.WebSocketStatus { - pluginName := (*websockets.WebSockets)(nil).Name() - if plugin, ok := sm.transports[pluginName]; ok { - return plugin.(*websockets.WebSockets).GetStatus() - } - return &core.WebSocketStatus{Enabled: false} -} From 9635e2bbefade9c7b24669f9ca845b7ffb36ef8f Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Mon, 6 Jun 2022 11:14:38 -0400 Subject: [PATCH 11/33] Group orchestrator config into a struct Signed-off-by: Andrew Richardson --- internal/namespace/manager.go | 162 ++++++++++----------- internal/orchestrator/chart.go | 2 +- internal/orchestrator/data_query.go | 62 ++++---- internal/orchestrator/orchestrator.go | 119 ++++++++------- internal/orchestrator/orchestrator_test.go | 21 +-- internal/orchestrator/status.go | 16 +- internal/orchestrator/status_test.go | 8 +- internal/orchestrator/subscriptions.go | 6 +- internal/orchestrator/txn_status.go | 8 +- 9 files changed, 198 insertions(+), 206 deletions(-) diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index a7a98ef313..9b0259211b 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -66,15 +66,8 @@ type Manager interface { } type namespace struct { - orchestrator orchestrator.Orchestrator - defaultKey string - multiparty orchestrator.MultipartyConfig - database orchestrator.DatabasePlugin - blockchain orchestrator.BlockchainPlugin - dataexchange orchestrator.DataexchangePlugin - sharedstorage orchestrator.SharedStoragePlugin - identity orchestrator.IdentityPlugin - tokens map[string]orchestrator.TokensPlugin + orchestrator orchestrator.Orchestrator + config orchestrator.Config } type namespaceManager struct { @@ -133,7 +126,7 @@ func (nm *namespaceManager) Init(ctx context.Context, cancelCtx context.CancelFu // Start an orchestrator per namespace for name, ns := range nm.namespaces { - or := orchestrator.NewOrchestrator(name, ns.defaultKey, ns.multiparty, ns.blockchain, ns.database, ns.sharedstorage, ns.dataexchange, ns.tokens, ns.identity, nm.metrics, nm.adminEvents) + or := orchestrator.NewOrchestrator(name, ns.config, nm.metrics, nm.adminEvents) if err = or.Init(ctx, cancelCtx); err != nil { return err } @@ -227,22 +220,21 @@ func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[s tokensConfigArraySize := tokensConfig.ArraySize() for i := 0; i < tokensConfigArraySize; i++ { config := tokensConfig.ArrayEntry(i) - if err = nm.validatePluginConfig(ctx, config, "tokens"); err != nil { + name, pluginType, err := nm.validatePluginConfig(ctx, config, "tokens") + if err != nil { return nil, err } - pluginType := config.GetString(coreconfig.PluginConfigType) plugin, err := tifactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } - tokensPlugin := orchestrator.TokensPlugin{ + plugins[name] = orchestrator.TokensPlugin{ + Name: name, Plugin: plugin, Config: config.SubSection(pluginType), - Name: config.GetString(coreconfig.PluginConfigName), } - plugins[config.GetString(coreconfig.PluginConfigName)] = tokensPlugin } // If there still is no tokens config, check the deprecated structure for config @@ -255,7 +247,7 @@ func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[s for i := 0; i < tokensConfigArraySize; i++ { deprecatedConfig := deprecatedTokensConfig.ArrayEntry(i) name := deprecatedConfig.GetString(coreconfig.PluginConfigName) - pluginName := deprecatedConfig.GetString(tokens.TokensConfigPlugin) + pluginType := deprecatedConfig.GetString(tokens.TokensConfigPlugin) if name == "" { return nil, i18n.NewError(ctx, coremsgs.MsgMissingTokensPluginConfig) } @@ -263,18 +255,16 @@ func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[s return nil, err } - log.L(ctx).Infof("Loading tokens plugin name=%s plugin=%s", name, pluginName) - plugin, err := tifactory.GetPlugin(ctx, pluginName) + plugin, err := tifactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } - tokensPlugin := orchestrator.TokensPlugin{ + plugins[name] = orchestrator.TokensPlugin{ + Name: name, Plugin: plugin, Config: deprecatedConfig, - Name: name, } - plugins[name] = tokensPlugin } } @@ -286,22 +276,21 @@ func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map dbConfigArraySize := databaseConfig.ArraySize() for i := 0; i < dbConfigArraySize; i++ { config := databaseConfig.ArrayEntry(i) - if err = nm.validatePluginConfig(ctx, config, "database"); err != nil { + name, pluginType, err := nm.validatePluginConfig(ctx, config, "database") + if err != nil { return nil, err } - pluginType := config.GetString(coreconfig.PluginConfigType) plugin, err := difactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } - dbPlugin := orchestrator.DatabasePlugin{ + plugins[name] = orchestrator.DatabasePlugin{ + Name: name, Plugin: plugin, Config: config.SubSection(pluginType), } - - plugins[config.GetString(coreconfig.PluginConfigName)] = dbPlugin } // check for deprecated config @@ -311,36 +300,35 @@ func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map if err != nil { return nil, err } - deprecatedPluginName := "database_0" - dbPlugin := orchestrator.DatabasePlugin{ + name := "database_0" + plugins[name] = orchestrator.DatabasePlugin{ + Name: name, Plugin: plugin, Config: deprecatedDatabaseConfig.SubSection(pluginType), } - - plugins[deprecatedPluginName] = dbPlugin } return plugins, err } -func (nm *namespaceManager) validatePluginConfig(ctx context.Context, config config.Section, sectionName string) error { - name := config.GetString(coreconfig.PluginConfigName) - pluginType := config.GetString(coreconfig.PluginConfigType) +func (nm *namespaceManager) validatePluginConfig(ctx context.Context, config config.Section, sectionName string) (name, pluginType string, err error) { + name = config.GetString(coreconfig.PluginConfigName) + pluginType = config.GetString(coreconfig.PluginConfigType) if name == "" || pluginType == "" { - return i18n.NewError(ctx, coremsgs.MsgInvalidPluginConfiguration, sectionName) + return "", "", i18n.NewError(ctx, coremsgs.MsgInvalidPluginConfiguration, sectionName) } if err := core.ValidateFFNameField(ctx, name, "name"); err != nil { - return err + return "", "", err } if _, ok := nm.pluginNames[name]; ok { - return i18n.NewError(ctx, coremsgs.MsgDuplicatePluginName, name) + return "", "", i18n.NewError(ctx, coremsgs.MsgDuplicatePluginName, name) } nm.pluginNames[name] = true - return nil + return name, pluginType, nil } func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins map[string]orchestrator.DataexchangePlugin, err error) { @@ -348,37 +336,37 @@ func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins dxConfigArraySize := dataexchangeConfig.ArraySize() for i := 0; i < dxConfigArraySize; i++ { config := dataexchangeConfig.ArrayEntry(i) - if err = nm.validatePluginConfig(ctx, config, "dataexchange"); err != nil { + name, pluginType, err := nm.validatePluginConfig(ctx, config, "dataexchange") + if err != nil { return nil, err } - pluginType := config.GetString(coreconfig.PluginConfigType) + plugin, err := dxfactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } - dxPlugin := orchestrator.DataexchangePlugin{ + + plugins[name] = orchestrator.DataexchangePlugin{ + Name: name, Plugin: plugin, Config: config.SubSection(pluginType), } - - plugins[config.GetString(coreconfig.PluginConfigName)] = dxPlugin } if len(plugins) == 0 { log.L(ctx).Warnf("Your data exchange config uses a deprecated configuration structure - the data exchange configuration has been moved under the 'plugins' section") - deprecatedPluginName := "dataexchange_0" pluginType := deprecatedDataexchangeConfig.GetString(coreconfig.PluginConfigType) plugin, err := dxfactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } - dxPlugin := orchestrator.DataexchangePlugin{ + name := "dataexchange_0" + plugins[name] = orchestrator.DataexchangePlugin{ + Name: name, Plugin: plugin, Config: deprecatedDataexchangeConfig.SubSection(pluginType), } - - plugins[deprecatedPluginName] = dxPlugin } return plugins, err @@ -389,20 +377,21 @@ func (nm *namespaceManager) getIdentityPlugins(ctx context.Context) (plugins map configSize := identityConfig.ArraySize() for i := 0; i < configSize; i++ { config := identityConfig.ArrayEntry(i) - if err = nm.validatePluginConfig(ctx, config, "identity"); err != nil { + name, pluginType, err := nm.validatePluginConfig(ctx, config, "identity") + if err != nil { return nil, err } - pluginType := config.GetString(coreconfig.PluginConfigType) + plugin, err := iifactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } - idPlugin := orchestrator.IdentityPlugin{ + plugins[name] = orchestrator.IdentityPlugin{ + Name: name, Plugin: plugin, Config: config.SubSection(pluginType), } - plugins[config.GetString(coreconfig.PluginConfigName)] = idPlugin } return plugins, err @@ -413,37 +402,37 @@ func (nm *namespaceManager) getBlockchainPlugins(ctx context.Context) (plugins m blockchainConfigArraySize := blockchainConfig.ArraySize() for i := 0; i < blockchainConfigArraySize; i++ { config := blockchainConfig.ArrayEntry(i) - if err = nm.validatePluginConfig(ctx, config, "blockchain"); err != nil { + name, pluginType, err := nm.validatePluginConfig(ctx, config, "blockchain") + if err != nil { return nil, err } - pluginType := config.GetString(coreconfig.PluginConfigType) plugin, err := bifactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } - bcPlugin := orchestrator.BlockchainPlugin{ + plugins[name] = orchestrator.BlockchainPlugin{ + Name: name, Plugin: plugin, Config: config.SubSection(pluginType), } - plugins[config.GetString(coreconfig.PluginConfigName)] = bcPlugin } // check deprecated config if len(plugins) == 0 { - deprecatedPluginName := "blockchain_0" pluginType := deprecatedBlockchainConfig.GetString(coreconfig.PluginConfigType) plugin, err := bifactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } - bcPlugin := orchestrator.BlockchainPlugin{ + name := "blockchain_0" + plugins[name] = orchestrator.BlockchainPlugin{ + Name: name, Plugin: plugin, Config: deprecatedBlockchainConfig.SubSection(pluginType), } - plugins[deprecatedPluginName] = bcPlugin } return plugins, err @@ -454,36 +443,37 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin configSize := sharedstorageConfig.ArraySize() for i := 0; i < configSize; i++ { config := sharedstorageConfig.ArrayEntry(i) - if err = nm.validatePluginConfig(ctx, config, "sharedstorage"); err != nil { + name, pluginType, err := nm.validatePluginConfig(ctx, config, "sharedstorage") + if err != nil { return nil, err } - pluginType := config.GetString(coreconfig.PluginConfigType) + plugin, err := ssfactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } - ssPlugin := orchestrator.SharedStoragePlugin{ + plugins[name] = orchestrator.SharedStoragePlugin{ + Name: name, Plugin: plugin, Config: config.SubSection(pluginType), } - plugins[config.GetString(coreconfig.PluginConfigName)] = ssPlugin } // check deprecated config if len(plugins) == 0 { - deprecatedPluginName := "sharedstorage_0" pluginType := deprecatedSharedStorageConfig.GetString(coreconfig.PluginConfigType) plugin, err := ssfactory.GetPlugin(ctx, pluginType) if err != nil { return nil, err } - ssPlugin := orchestrator.SharedStoragePlugin{ + name := "sharedstorage_0" + plugins[name] = orchestrator.SharedStoragePlugin{ + Name: name, Plugin: plugin, Config: deprecatedSharedStorageConfig.SubSection(pluginType), } - plugins[deprecatedPluginName] = ssPlugin } return plugins, err @@ -574,31 +564,30 @@ func (nm *namespaceManager) buildAndValidateNamespaces(ctx context.Context, name } } - defaultKey := conf.GetString(coreconfig.NamespaceDefaultKey) + config := orchestrator.Config{ + DefaultKey: conf.GetString(coreconfig.NamespaceDefaultKey), + Tokens: make(map[string]orchestrator.TokensPlugin), + } if multiparty.(bool) { - config := orchestrator.MultipartyConfig{ + config.Multiparty = orchestrator.MultipartyConfig{ Enabled: true, OrgName: orgName, OrgKey: orgKey, OrgDesc: orgDesc, } - return nm.validateMultiPartyConfig(ctx, name, defaultKey, config, plugins) + return nm.validateMultiPartyConfig(ctx, name, config, plugins) } - return nm.validateGatewayConfig(ctx, name, defaultKey, plugins) + return nm.validateGatewayConfig(ctx, name, config, plugins) } -func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name, defaultKey string, config orchestrator.MultipartyConfig, plugins []string) error { +func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name string, config orchestrator.Config, plugins []string) error { var dbPlugin bool var ssPlugin bool var dxPlugin bool var bcPlugin bool - ns := &namespace{ - tokens: make(map[string]orchestrator.TokensPlugin), - multiparty: config, - defaultKey: defaultKey, - } + ns := &namespace{config: config} for _, pluginName := range plugins { if instance, ok := nm.blockchains[pluginName]; ok { @@ -606,7 +595,7 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name, return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") } bcPlugin = true - ns.blockchain = instance + ns.config.Blockchain = instance continue } if instance, ok := nm.dataexchanges[pluginName]; ok { @@ -614,7 +603,7 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name, return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "dataexchange") } dxPlugin = true - ns.dataexchange = instance + ns.config.Dataexchange = instance continue } if instance, ok := nm.sharedstorages[pluginName]; ok { @@ -622,7 +611,7 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name, return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "sharedstorage") } ssPlugin = true - ns.sharedstorage = instance + ns.config.Sharedstorage = instance continue } if instance, ok := nm.databases[pluginName]; ok { @@ -630,15 +619,15 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name, return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") } dbPlugin = true - ns.database = instance + ns.config.Database = instance continue } if instance, ok := nm.tokens[pluginName]; ok { - ns.tokens[pluginName] = instance + ns.config.Tokens[pluginName] = instance continue } if instance, ok := nm.identities[pluginName]; ok { - ns.identity = instance + ns.config.Identity = instance continue } @@ -653,14 +642,11 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name, return nil } -func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name, defaultKey string, plugins []string) error { +func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name string, config orchestrator.Config, plugins []string) error { var dbPlugin bool var bcPlugin bool - ns := &namespace{ - tokens: make(map[string]orchestrator.TokensPlugin), - defaultKey: defaultKey, - } + ns := &namespace{config: config} for _, pluginName := range plugins { if instance, ok := nm.blockchains[pluginName]; ok { @@ -668,7 +654,7 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name, def return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") } bcPlugin = true - ns.blockchain = instance + ns.config.Blockchain = instance continue } if _, ok := nm.dataexchanges[pluginName]; ok { @@ -682,11 +668,11 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name, def return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") } dbPlugin = true - ns.database = instance + ns.config.Database = instance continue } if instance, ok := nm.tokens[pluginName]; ok { - ns.tokens[pluginName] = instance + ns.config.Tokens[pluginName] = instance continue } diff --git a/internal/orchestrator/chart.go b/internal/orchestrator/chart.go index 9bde90bd5a..31f4cefb33 100644 --- a/internal/orchestrator/chart.go +++ b/internal/orchestrator/chart.go @@ -49,7 +49,7 @@ func (or *orchestrator) GetChartHistogram(ctx context.Context, ns string, startT intervals := or.getHistogramIntervals(startTime, endTime, buckets) - histogram, err := or.database.Plugin.GetChartHistogram(ctx, ns, intervals, collection) + histogram, err := or.database.GetChartHistogram(ctx, ns, intervals, collection) if err != nil { return nil, err } diff --git a/internal/orchestrator/data_query.go b/internal/orchestrator/data_query.go index 430ad0b931..2f678c3149 100644 --- a/internal/orchestrator/data_query.go +++ b/internal/orchestrator/data_query.go @@ -50,7 +50,7 @@ func (or *orchestrator) verifyIDAndNamespace(ctx context.Context, ns, id string) } func (or *orchestrator) GetNamespace(ctx context.Context, ns string) (*core.Namespace, error) { - return or.database.Plugin.GetNamespace(ctx, ns) + return or.database.GetNamespace(ctx, ns) } func (or *orchestrator) GetTransactionByID(ctx context.Context, ns, id string) (*core.Transaction, error) { @@ -58,7 +58,7 @@ func (or *orchestrator) GetTransactionByID(ctx context.Context, ns, id string) ( if err != nil { return nil, err } - tx, err := or.database.Plugin.GetTransactionByID(ctx, u) + tx, err := or.database.GetTransactionByID(ctx, u) if err == nil && tx != nil { err = or.checkNamespace(ctx, ns, tx.Namespace) } @@ -75,7 +75,7 @@ func (or *orchestrator) GetTransactionOperations(ctx context.Context, ns, id str fb.Eq("tx", u), fb.Eq("namespace", ns), ) - return or.database.Plugin.GetOperations(ctx, filter) + return or.database.GetOperations(ctx, filter) } func (or *orchestrator) getMessageByID(ctx context.Context, ns, id string) (*core.Message, error) { @@ -83,7 +83,7 @@ func (or *orchestrator) getMessageByID(ctx context.Context, ns, id string) (*cor if err != nil { return nil, err } - msg, err := or.database.Plugin.GetMessageByID(ctx, u) + msg, err := or.database.GetMessageByID(ctx, u) if err == nil && msg == nil { return nil, i18n.NewError(ctx, coremsgs.Msg404NotFound) } @@ -126,7 +126,7 @@ func (or *orchestrator) GetBatchByID(ctx context.Context, ns, id string) (*core. if err != nil { return nil, err } - b, err := or.database.Plugin.GetBatchByID(ctx, u) + b, err := or.database.GetBatchByID(ctx, u) if err == nil && b != nil { err = or.checkNamespace(ctx, ns, b.Namespace) } @@ -138,7 +138,7 @@ func (or *orchestrator) GetDataByID(ctx context.Context, ns, id string) (*core.D if err != nil { return nil, err } - d, err := or.database.Plugin.GetDataByID(ctx, u, true) + d, err := or.database.GetDataByID(ctx, u, true) if err == nil && d != nil { err = or.checkNamespace(ctx, ns, d.Namespace) } @@ -150,7 +150,7 @@ func (or *orchestrator) GetDatatypeByID(ctx context.Context, ns, id string) (*co if err != nil { return nil, err } - dt, err := or.database.Plugin.GetDatatypeByID(ctx, u) + dt, err := or.database.GetDatatypeByID(ctx, u) if err == nil && dt != nil { err = or.checkNamespace(ctx, ns, dt.Namespace) } @@ -164,7 +164,7 @@ func (or *orchestrator) GetDatatypeByName(ctx context.Context, ns, name, version if err := core.ValidateFFNameFieldNoUUID(ctx, name, "name"); err != nil { return nil, err } - dt, err := or.database.Plugin.GetDatatypeByName(ctx, ns, name, version) + dt, err := or.database.GetDatatypeByName(ctx, ns, name, version) if err == nil && dt != nil { err = or.checkNamespace(ctx, ns, dt.Namespace) } @@ -176,7 +176,7 @@ func (or *orchestrator) GetOperationByIDNamespaced(ctx context.Context, ns, id s if err != nil { return nil, err } - o, err := or.database.Plugin.GetOperationByID(ctx, u) + o, err := or.database.GetOperationByID(ctx, u) if err == nil && o != nil { err = or.checkNamespace(ctx, ns, o.Namespace) } @@ -188,7 +188,7 @@ func (or *orchestrator) GetOperationByID(ctx context.Context, id string) (*core. if err != nil { return nil, err } - return or.database.Plugin.GetOperationByID(ctx, u) + return or.database.GetOperationByID(ctx, u) } func (or *orchestrator) GetEventByID(ctx context.Context, ns, id string) (*core.Event, error) { @@ -196,7 +196,7 @@ func (or *orchestrator) GetEventByID(ctx context.Context, ns, id string) (*core. if err != nil { return nil, err } - e, err := or.database.Plugin.GetEventByID(ctx, u) + e, err := or.database.GetEventByID(ctx, u) if err == nil && e != nil { err = or.checkNamespace(ctx, ns, e.Namespace) } @@ -204,7 +204,7 @@ func (or *orchestrator) GetEventByID(ctx context.Context, ns, id string) (*core. } func (or *orchestrator) GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) { - return or.database.Plugin.GetNamespaces(ctx, filter) + return or.database.GetNamespaces(ctx, filter) } func (or *orchestrator) scopeNS(ns string, filter database.AndFilter) database.AndFilter { @@ -213,17 +213,17 @@ func (or *orchestrator) scopeNS(ns string, filter database.AndFilter) database.A func (or *orchestrator) GetTransactions(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Transaction, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.Plugin.GetTransactions(ctx, filter) + return or.database.GetTransactions(ctx, filter) } func (or *orchestrator) GetMessages(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Message, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.Plugin.GetMessages(ctx, filter) + return or.database.GetMessages(ctx, filter) } func (or *orchestrator) GetMessagesWithData(ctx context.Context, ns string, filter database.AndFilter) ([]*core.MessageInOut, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - msgs, fr, err := or.database.Plugin.GetMessages(ctx, filter) + msgs, fr, err := or.database.GetMessages(ctx, filter) if err != nil { return nil, nil, err } @@ -255,7 +255,7 @@ func (or *orchestrator) getMessageTransactionID(ctx context.Context, ns, id stri if msg.BatchID == nil { return nil, i18n.NewError(ctx, coremsgs.MsgBatchNotSet) } - batch, err := or.database.Plugin.GetBatchByID(ctx, msg.BatchID) + batch, err := or.database.GetBatchByID(ctx, msg.BatchID) if err != nil { return nil, err } @@ -277,7 +277,7 @@ func (or *orchestrator) GetMessageTransaction(ctx context.Context, ns, id string if err != nil { return nil, err } - return or.database.Plugin.GetTransactionByID(ctx, txID) + return or.database.GetTransactionByID(ctx, txID) } func (or *orchestrator) GetMessageOperations(ctx context.Context, ns, id string) ([]*core.Operation, *database.FilterResult, error) { @@ -286,7 +286,7 @@ func (or *orchestrator) GetMessageOperations(ctx context.Context, ns, id string) return nil, nil, err } filter := database.OperationQueryFactory.NewFilter(ctx).Eq("tx", txID) - return or.database.Plugin.GetOperations(ctx, filter) + return or.database.GetOperations(ctx, filter) } func (or *orchestrator) GetMessageEvents(ctx context.Context, ns, id string, filter database.AndFilter) ([]*core.Event, *database.FilterResult, error) { @@ -303,17 +303,17 @@ func (or *orchestrator) GetMessageEvents(ctx context.Context, ns, id string, fil } filter = filter.Condition(filter.Builder().In("reference", referencedIDs)) // Execute the filter - return or.database.Plugin.GetEvents(ctx, filter) + return or.database.GetEvents(ctx, filter) } func (or *orchestrator) GetBatches(ctx context.Context, ns string, filter database.AndFilter) ([]*core.BatchPersisted, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.Plugin.GetBatches(ctx, filter) + return or.database.GetBatches(ctx, filter) } func (or *orchestrator) GetData(ctx context.Context, ns string, filter database.AndFilter) (core.DataArray, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.Plugin.GetData(ctx, filter) + return or.database.GetData(ctx, filter) } func (or *orchestrator) GetMessagesForData(ctx context.Context, ns, dataID string, filter database.AndFilter) ([]*core.Message, *database.FilterResult, error) { @@ -322,26 +322,26 @@ func (or *orchestrator) GetMessagesForData(ctx context.Context, ns, dataID strin if err != nil { return nil, nil, err } - return or.database.Plugin.GetMessagesForData(ctx, u, filter) + return or.database.GetMessagesForData(ctx, u, filter) } func (or *orchestrator) GetDatatypes(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Datatype, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.Plugin.GetDatatypes(ctx, filter) + return or.database.GetDatatypes(ctx, filter) } func (or *orchestrator) GetOperationsNamespaced(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Operation, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.Plugin.GetOperations(ctx, filter) + return or.database.GetOperations(ctx, filter) } func (or *orchestrator) GetOperations(ctx context.Context, filter database.AndFilter) ([]*core.Operation, *database.FilterResult, error) { - return or.database.Plugin.GetOperations(ctx, filter) + return or.database.GetOperations(ctx, filter) } func (or *orchestrator) GetEvents(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Event, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.Plugin.GetEvents(ctx, filter) + return or.database.GetEvents(ctx, filter) } func (or *orchestrator) GetBlockchainEventByID(ctx context.Context, ns, id string) (*core.BlockchainEvent, error) { @@ -349,7 +349,7 @@ func (or *orchestrator) GetBlockchainEventByID(ctx context.Context, ns, id strin if err != nil { return nil, err } - be, err := or.database.Plugin.GetBlockchainEventByID(ctx, u) + be, err := or.database.GetBlockchainEventByID(ctx, u) if err == nil && be != nil { err = or.checkNamespace(ctx, ns, be.Namespace) } @@ -357,7 +357,7 @@ func (or *orchestrator) GetBlockchainEventByID(ctx context.Context, ns, id strin } func (or *orchestrator) GetBlockchainEvents(ctx context.Context, ns string, filter database.AndFilter) ([]*core.BlockchainEvent, *database.FilterResult, error) { - return or.database.Plugin.GetBlockchainEvents(ctx, or.scopeNS(ns, filter)) + return or.database.GetBlockchainEvents(ctx, or.scopeNS(ns, filter)) } func (or *orchestrator) GetTransactionBlockchainEvents(ctx context.Context, ns, id string) ([]*core.BlockchainEvent, *database.FilterResult, error) { @@ -370,16 +370,16 @@ func (or *orchestrator) GetTransactionBlockchainEvents(ctx context.Context, ns, fb.Eq("tx.id", u), fb.Eq("namespace", ns), ) - return or.database.Plugin.GetBlockchainEvents(ctx, filter) + return or.database.GetBlockchainEvents(ctx, filter) } func (or *orchestrator) GetPins(ctx context.Context, filter database.AndFilter) ([]*core.Pin, *database.FilterResult, error) { - return or.database.Plugin.GetPins(ctx, filter) + return or.database.GetPins(ctx, filter) } func (or *orchestrator) GetEventsWithReferences(ctx context.Context, ns string, filter database.AndFilter) ([]*core.EnrichedEvent, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - events, fr, err := or.database.Plugin.GetEvents(ctx, filter) + events, fr, err := or.database.GetEvents(ctx, filter) if err != nil { return nil, nil, err } diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index e15848eac7..e523fb27ed 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -120,35 +120,38 @@ type Orchestrator interface { SubmitNetworkAction(ctx context.Context, ns string, action *core.NetworkAction) error } -// this is definitely not the right place for these structs -// maybe in the factories? type BlockchainPlugin struct { + Name string Plugin blockchain.Plugin Config config.Section } type DatabasePlugin struct { + Name string Plugin database.Plugin Config config.Section } type DataexchangePlugin struct { + Name string Plugin dataexchange.Plugin Config config.Section } type SharedStoragePlugin struct { + Name string Plugin sharedstorage.Plugin Config config.Section } type TokensPlugin struct { + Name string Plugin tokens.Plugin Config config.Section - Name string } type IdentityPlugin struct { + Name string Plugin idplugin.Plugin Config config.Section } @@ -160,19 +163,28 @@ type MultipartyConfig struct { OrgKey string } +type Config struct { + DefaultKey string + Multiparty MultipartyConfig + Blockchain BlockchainPlugin + Identity IdentityPlugin + Sharedstorage SharedStoragePlugin + Dataexchange DataexchangePlugin + Database DatabasePlugin + Tokens map[string]TokensPlugin +} + type orchestrator struct { ctx context.Context cancelCtx context.CancelFunc started bool namespace string - defaultKey string - multiparty MultipartyConfig - blockchain BlockchainPlugin + config Config + blockchain blockchain.Plugin identity identity.Manager - idPlugin IdentityPlugin - sharedstorage SharedStoragePlugin - dataexchange DataexchangePlugin - database DatabasePlugin + sharedstorage sharedstorage.Plugin + dataexchange dataexchange.Plugin + database database.Plugin events events.EventManager networkmap networkmap.Manager batch batch.Manager @@ -183,7 +195,7 @@ type orchestrator struct { syncasync syncasync.Bridge batchpin batchpin.Submitter assets assets.Manager - tokens map[string]TokensPlugin + tokens map[string]tokens.Plugin bc boundCallbacks contracts contracts.Manager node *fftypes.UUID @@ -194,20 +206,21 @@ type orchestrator struct { adminEvents adminevents.Manager } -func NewOrchestrator(ns, defaultKey string, multiparty MultipartyConfig, bc BlockchainPlugin, db DatabasePlugin, ss SharedStoragePlugin, dx DataexchangePlugin, tokens map[string]TokensPlugin, id IdentityPlugin, metrics metrics.Manager, adminEvents adminevents.Manager) Orchestrator { +func NewOrchestrator(ns string, config Config, metrics metrics.Manager, adminEvents adminevents.Manager) Orchestrator { or := &orchestrator{ namespace: ns, - defaultKey: defaultKey, - multiparty: multiparty, - blockchain: bc, - database: db, - sharedstorage: ss, - dataexchange: dx, - tokens: tokens, - idPlugin: id, + config: config, + blockchain: config.Blockchain.Plugin, + database: config.Database.Plugin, + sharedstorage: config.Sharedstorage.Plugin, + dataexchange: config.Dataexchange.Plugin, + tokens: make(map[string]tokens.Plugin, len(config.Tokens)), metrics: metrics, adminEvents: adminEvents, } + for name, ti := range config.Tokens { + or.tokens[name] = ti.Plugin + } return or } @@ -220,17 +233,17 @@ func (or *orchestrator) Init(ctx context.Context, cancelCtx context.CancelFunc) err = or.initComponents(ctx) } // Bind together the blockchain interface callbacks, with the events manager - or.bc.bi = or.blockchain.Plugin + or.bc.bi = or.blockchain or.bc.ei = or.events - or.bc.dx = or.dataexchange.Plugin - or.bc.ss = or.sharedstorage.Plugin + or.bc.dx = or.dataexchange + or.bc.ss = or.sharedstorage or.bc.om = or.operations return err } func (or *orchestrator) Start() (err error) { var ns *core.Namespace - ns, err = or.database.Plugin.GetNamespace(or.ctx, or.namespace) + ns, err = or.database.GetNamespace(or.ctx, or.namespace) if err == nil { if ns == nil { ns = &core.Namespace{ @@ -238,13 +251,13 @@ func (or *orchestrator) Start() (err error) { Created: fftypes.Now(), } } - err = or.blockchain.Plugin.ConfigureContract(or.ctx, &ns.Contracts) + err = or.blockchain.ConfigureContract(or.ctx, &ns.Contracts) } if err == nil { - err = or.blockchain.Plugin.Start() + err = or.blockchain.Start() } if err == nil { - err = or.database.Plugin.UpsertNamespace(or.ctx, ns, true) + err = or.database.UpsertNamespace(or.ctx, ns, true) } if err == nil { err = or.batch.Start() @@ -266,7 +279,7 @@ func (or *orchestrator) Start() (err error) { } if err == nil { for _, el := range or.tokens { - if err = el.Plugin.Start(); err != nil { + if err = el.Start(); err != nil { break } } @@ -343,18 +356,18 @@ func (or *orchestrator) Operations() operations.Manager { } func (or *orchestrator) initPlugins(ctx context.Context) (err error) { - err = or.database.Plugin.Init(ctx, or.database.Config, or) + err = or.database.Init(ctx, or.config.Database.Config, or) if err != nil { return err } - err = or.blockchain.Plugin.Init(ctx, or.blockchain.Config, &or.bc, or.metrics) + err = or.blockchain.Init(ctx, or.config.Blockchain.Config, &or.bc, or.metrics) if err != nil { return err } fb := database.IdentityQueryFactory.NewFilter(ctx) - nodes, _, err := or.database.Plugin.GetIdentities(ctx, fb.And( + nodes, _, err := or.database.GetIdentities(ctx, fb.And( fb.Eq("type", core.IdentityTypeNode), )) if err != nil { @@ -365,18 +378,18 @@ func (or *orchestrator) initPlugins(ctx context.Context) (err error) { nodeInfo[i] = node.Profile } - err = or.dataexchange.Plugin.Init(ctx, or.dataexchange.Config, nodeInfo, &or.bc) + err = or.dataexchange.Init(ctx, or.config.Dataexchange.Config, nodeInfo, &or.bc) if err != nil { return err } - err = or.sharedstorage.Plugin.Init(ctx, or.sharedstorage.Config, &or.bc) + err = or.sharedstorage.Init(ctx, or.config.Sharedstorage.Config, &or.bc) if err != nil { return err } - for _, token := range or.tokens { - err = token.Plugin.Init(ctx, token.Name, token.Config, &or.bc) + for name, token := range or.tokens { + err = token.Init(ctx, name, or.config.Tokens[name].Config, &or.bc) } return err @@ -385,97 +398,93 @@ func (or *orchestrator) initPlugins(ctx context.Context) (err error) { func (or *orchestrator) initComponents(ctx context.Context) (err error) { if or.data == nil { - or.data, err = data.NewDataManager(ctx, or.database.Plugin, or.sharedstorage.Plugin, or.dataexchange.Plugin) + or.data, err = data.NewDataManager(ctx, or.database, or.sharedstorage, or.dataexchange) if err != nil { return err } } if or.txHelper == nil { - or.txHelper = txcommon.NewTransactionHelper(or.database.Plugin, or.data) + or.txHelper = txcommon.NewTransactionHelper(or.database, or.data) } if or.identity == nil { - or.identity, err = identity.NewIdentityManager(ctx, or.defaultKey, or.multiparty.OrgName, or.multiparty.OrgKey, or.database.Plugin, or.blockchain.Plugin, or.data) + or.identity, err = identity.NewIdentityManager(ctx, or.config.DefaultKey, or.config.Multiparty.OrgName, or.config.Multiparty.OrgKey, or.database, or.blockchain, or.data) if err != nil { return err } } if or.batch == nil { - or.batch, err = batch.NewBatchManager(ctx, or, or.database.Plugin, or.data, or.txHelper) + or.batch, err = batch.NewBatchManager(ctx, or, or.database, or.data, or.txHelper) if err != nil { return err } } if or.operations == nil { - if or.operations, err = operations.NewOperationsManager(ctx, or.database.Plugin, or.txHelper); err != nil { + if or.operations, err = operations.NewOperationsManager(ctx, or.database, or.txHelper); err != nil { return err } } - or.syncasync = syncasync.NewSyncAsyncBridge(ctx, or.database.Plugin, or.data) + or.syncasync = syncasync.NewSyncAsyncBridge(ctx, or.database, or.data) if or.batchpin == nil { - if or.batchpin, err = batchpin.NewBatchPinSubmitter(ctx, or.database.Plugin, or.identity, or.blockchain.Plugin, or.metrics, or.operations); err != nil { + if or.batchpin, err = batchpin.NewBatchPinSubmitter(ctx, or.database, or.identity, or.blockchain, or.metrics, or.operations); err != nil { return err } } if or.messaging == nil { - if or.messaging, err = privatemessaging.NewPrivateMessaging(ctx, or.database.Plugin, or.identity, or.dataexchange.Plugin, or.blockchain.Plugin, or.batch, or.data, or.syncasync, or.batchpin, or.metrics, or.operations); err != nil { + if or.messaging, err = privatemessaging.NewPrivateMessaging(ctx, or.database, or.identity, or.dataexchange, or.blockchain, or.batch, or.data, or.syncasync, or.batchpin, or.metrics, or.operations); err != nil { return err } } if or.broadcast == nil { - if or.broadcast, err = broadcast.NewBroadcastManager(ctx, or.database.Plugin, or.identity, or.data, or.blockchain.Plugin, or.dataexchange.Plugin, or.sharedstorage.Plugin, or.batch, or.syncasync, or.batchpin, or.metrics, or.operations); err != nil { + if or.broadcast, err = broadcast.NewBroadcastManager(ctx, or.database, or.identity, or.data, or.blockchain, or.dataexchange, or.sharedstorage, or.batch, or.syncasync, or.batchpin, or.metrics, or.operations); err != nil { return err } } if or.assets == nil { - plugins := make(map[string]tokens.Plugin, len(or.tokens)) - for _, v := range or.tokens { - plugins[v.Name] = v.Plugin - } - or.assets, err = assets.NewAssetManager(ctx, or.database.Plugin, or.identity, or.data, or.syncasync, or.broadcast, or.messaging, plugins, or.metrics, or.operations, or.txHelper) + or.assets, err = assets.NewAssetManager(ctx, or.database, or.identity, or.data, or.syncasync, or.broadcast, or.messaging, or.tokens, or.metrics, or.operations, or.txHelper) if err != nil { return err } } if or.contracts == nil { - or.contracts, err = contracts.NewContractManager(ctx, or.database.Plugin, or.broadcast, or.identity, or.blockchain.Plugin, or.operations, or.txHelper, or.syncasync) + or.contracts, err = contracts.NewContractManager(ctx, or.database, or.broadcast, or.identity, or.blockchain, or.operations, or.txHelper, or.syncasync) if err != nil { return err } } if or.definitions == nil { - or.definitions, err = definitions.NewDefinitionHandler(ctx, or.database.Plugin, or.blockchain.Plugin, or.dataexchange.Plugin, or.data, or.identity, or.assets, or.contracts) + or.definitions, err = definitions.NewDefinitionHandler(ctx, or.database, or.blockchain, or.dataexchange, or.data, or.identity, or.assets, or.contracts) if err != nil { return err } } if or.sharedDownload == nil { - or.sharedDownload, err = shareddownload.NewDownloadManager(ctx, or.database.Plugin, or.sharedstorage.Plugin, or.dataexchange.Plugin, or.operations, &or.bc) + or.sharedDownload, err = shareddownload.NewDownloadManager(ctx, or.database, or.sharedstorage, or.dataexchange, or.operations, &or.bc) if err != nil { return err } } if or.events == nil { - or.events, err = events.NewEventManager(ctx, or, or.sharedstorage.Plugin, or.database.Plugin, or.blockchain.Plugin, or.identity, or.definitions, or.data, or.broadcast, or.messaging, or.assets, or.sharedDownload, or.metrics, or.txHelper) + or.events, err = events.NewEventManager(ctx, or, or.sharedstorage, or.database, or.blockchain, or.identity, or.definitions, or.data, or.broadcast, or.messaging, or.assets, or.sharedDownload, or.metrics, or.txHelper) if err != nil { return err } } if or.networkmap == nil { - or.networkmap, err = networkmap.NewNetworkMap(ctx, or.multiparty.OrgName, or.multiparty.OrgDesc, or.database.Plugin, or.data, or.broadcast, or.dataexchange.Plugin, or.identity, or.syncasync) + or.networkmap, err = networkmap.NewNetworkMap(ctx, or.config.Multiparty.OrgName, or.config.Multiparty.OrgDesc, or.database, or.data, or.broadcast, or.dataexchange, or.identity, or.syncasync) if err != nil { return err } @@ -499,5 +508,5 @@ func (or *orchestrator) SubmitNetworkAction(ctx context.Context, ns string, acti } else { return i18n.NewError(ctx, coremsgs.MsgUnrecognizedNetworkAction, action.Type) } - return or.blockchain.Plugin.SubmitNetworkAction(ctx, fftypes.NewUUID(), key, action.Type) + return or.blockchain.SubmitNetworkAction(ctx, fftypes.NewUUID(), key, action.Type) } diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index fd018e2412..d00f9d8b9a 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -43,6 +43,7 @@ import ( "github.com/hyperledger/firefly/mocks/sharedstoragemocks" "github.com/hyperledger/firefly/mocks/tokenmocks" "github.com/hyperledger/firefly/mocks/txcommonmocks" + "github.com/hyperledger/firefly/pkg/tokens" "github.com/stretchr/testify/assert" ) @@ -131,21 +132,20 @@ func newTestOrchestrator() *testOrchestrator { mae: &admineventsmocks.Manager{}, mdh: &definitionsmocks.DefinitionHandler{}, } - tor.orchestrator.database.Plugin = tor.mdi + tor.orchestrator.database = tor.mdi tor.orchestrator.data = tor.mdm tor.orchestrator.batch = tor.mba tor.orchestrator.broadcast = tor.mbm tor.orchestrator.events = tor.mem tor.orchestrator.networkmap = tor.mnm - tor.orchestrator.sharedstorage.Plugin = tor.mps + tor.orchestrator.sharedstorage = tor.mps tor.orchestrator.messaging = tor.mpm tor.orchestrator.identity = tor.mim - tor.orchestrator.idPlugin.Plugin = tor.mii - tor.orchestrator.dataexchange.Plugin = tor.mdx + tor.orchestrator.dataexchange = tor.mdx tor.orchestrator.assets = tor.mam tor.orchestrator.contracts = tor.mcm - tor.orchestrator.tokens = map[string]TokensPlugin{"token": {Plugin: tor.mti}} - tor.orchestrator.blockchain.Plugin = tor.mbi + tor.orchestrator.tokens = map[string]tokens.Plugin{"token": tor.mti} + tor.orchestrator.blockchain = tor.mbi tor.orchestrator.metrics = tor.mmi tor.orchestrator.operations = tor.mom tor.orchestrator.batchpin = tor.mbp @@ -169,14 +169,7 @@ func newTestOrchestrator() *testOrchestrator { func TestNewOrchestrator(t *testing.T) { or := NewOrchestrator( "ns1", - "0x1234", - MultipartyConfig{}, - BlockchainPlugin{}, - DatabasePlugin{}, - SharedStoragePlugin{}, - DataexchangePlugin{}, - map[string]TokensPlugin{}, - IdentityPlugin{}, + Config{}, &metricsmocks.Manager{}, &admineventsmocks.Manager{}, ) diff --git a/internal/orchestrator/status.go b/internal/orchestrator/status.go index 263f5a4a11..fd98695d62 100644 --- a/internal/orchestrator/status.go +++ b/internal/orchestrator/status.go @@ -34,28 +34,32 @@ func (or *orchestrator) getPlugins() core.NodeStatusPlugins { for name, plugin := range or.tokens { tokensArray = append(tokensArray, &core.NodeStatusPlugin{ Name: name, - PluginType: plugin.Plugin.Name(), + PluginType: plugin.Name(), }) } blockchainsArray := make([]*core.NodeStatusPlugin, 0) blockchainsArray = append(blockchainsArray, &core.NodeStatusPlugin{ - PluginType: or.blockchain.Plugin.Name(), + Name: or.config.Blockchain.Name, + PluginType: or.blockchain.Name(), }) databasesArray := make([]*core.NodeStatusPlugin, 0) databasesArray = append(databasesArray, &core.NodeStatusPlugin{ - PluginType: or.database.Plugin.Name(), + Name: or.config.Database.Name, + PluginType: or.database.Name(), }) sharedstorageArray := make([]*core.NodeStatusPlugin, 0) sharedstorageArray = append(sharedstorageArray, &core.NodeStatusPlugin{ - PluginType: or.sharedstorage.Plugin.Name(), + Name: or.config.Sharedstorage.Name, + PluginType: or.sharedstorage.Name(), }) dataexchangeArray := make([]*core.NodeStatusPlugin, 0) dataexchangeArray = append(dataexchangeArray, &core.NodeStatusPlugin{ - PluginType: or.dataexchange.Plugin.Name(), + Name: or.config.Dataexchange.Name, + PluginType: or.dataexchange.Name(), }) return core.NodeStatusPlugins{ @@ -97,7 +101,7 @@ func (or *orchestrator) GetStatus(ctx context.Context, ns string) (status *core. Name: config.GetString(coreconfig.NodeName), }, Org: core.NodeStatusOrg{ - Name: or.multiparty.OrgName, + Name: or.config.Multiparty.OrgName, }, Plugins: or.getPlugins(), } diff --git a/internal/orchestrator/status_test.go b/internal/orchestrator/status_test.go index 361bf1a540..ec45fdcb17 100644 --- a/internal/orchestrator/status_test.go +++ b/internal/orchestrator/status_test.go @@ -112,7 +112,7 @@ func TestGetStatusRegistered(t *testing.T) { }}, }, nil, nil) - or.multiparty.OrgName = "org1" + or.config.Multiparty.OrgName = "org1" mem := or.events.(*eventmocks.EventManager) mem.On("GetPlugins").Return(mockEventPlugins) @@ -216,7 +216,7 @@ func TestGetStatusWrongNodeOwner(t *testing.T) { }}, }, nil, nil) - or.multiparty.OrgName = "org1" + or.config.Multiparty.OrgName = "org1" mem := or.events.(*eventmocks.EventManager) mem.On("GetPlugins").Return(mockEventPlugins) @@ -247,7 +247,7 @@ func TestGetStatusUnregistered(t *testing.T) { mim := or.identity.(*identitymanagermocks.Manager) mim.On("GetMultipartyRootOrg", or.ctx, "ns").Return(nil, fmt.Errorf("pop")) - or.multiparty.OrgName = "org1" + or.config.Multiparty.OrgName = "org1" mem := or.events.(*eventmocks.EventManager) mem.On("GetPlugins").Return(mockEventPlugins) @@ -294,7 +294,7 @@ func TestGetStatusOrgOnlyRegistered(t *testing.T) { }}, }, nil, nil) - or.multiparty.OrgName = "org1" + or.config.Multiparty.OrgName = "org1" mem := or.events.(*eventmocks.EventManager) mem.On("GetPlugins").Return(mockEventPlugins) diff --git a/internal/orchestrator/subscriptions.go b/internal/orchestrator/subscriptions.go index 4400538b1f..e882dc4f8a 100644 --- a/internal/orchestrator/subscriptions.go +++ b/internal/orchestrator/subscriptions.go @@ -58,7 +58,7 @@ func (or *orchestrator) DeleteSubscription(ctx context.Context, ns, id string) e if err != nil { return err } - sub, err := or.database.Plugin.GetSubscriptionByID(ctx, u) + sub, err := or.database.GetSubscriptionByID(ctx, u) if err != nil { return err } @@ -70,7 +70,7 @@ func (or *orchestrator) DeleteSubscription(ctx context.Context, ns, id string) e func (or *orchestrator) GetSubscriptions(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Subscription, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.Plugin.GetSubscriptions(ctx, filter) + return or.database.GetSubscriptions(ctx, filter) } func (or *orchestrator) GetSubscriptionByID(ctx context.Context, ns, id string) (*core.Subscription, error) { @@ -78,5 +78,5 @@ func (or *orchestrator) GetSubscriptionByID(ctx context.Context, ns, id string) if err != nil { return nil, err } - return or.database.Plugin.GetSubscriptionByID(ctx, u) + return or.database.GetSubscriptionByID(ctx, u) } diff --git a/internal/orchestrator/txn_status.go b/internal/orchestrator/txn_status.go index 554163a4d2..fac5fcd61f 100644 --- a/internal/orchestrator/txn_status.go +++ b/internal/orchestrator/txn_status.go @@ -101,7 +101,7 @@ func (or *orchestrator) GetTransactionStatus(ctx context.Context, ns, id string) updateStatus(result, core.OpStatusPending) } f := database.BatchQueryFactory.NewFilter(ctx) - switch batches, _, err := or.database.Plugin.GetBatches(ctx, f.Eq("tx.id", id)); { + switch batches, _, err := or.database.GetBatches(ctx, f.Eq("tx.id", id)); { case err != nil: return nil, err case len(batches) == 0: @@ -120,7 +120,7 @@ func (or *orchestrator) GetTransactionStatus(ctx context.Context, ns, id string) case core.TransactionTypeTokenPool: // Note: no assumptions about blockchain events here (may or may not contain one) f := database.TokenPoolQueryFactory.NewFilter(ctx) - switch pools, _, err := or.database.Plugin.GetTokenPools(ctx, f.Eq("tx.id", id)); { + switch pools, _, err := or.database.GetTokenPools(ctx, f.Eq("tx.id", id)); { case err != nil: return nil, err case len(pools) == 0: @@ -150,7 +150,7 @@ func (or *orchestrator) GetTransactionStatus(ctx context.Context, ns, id string) updateStatus(result, core.OpStatusPending) } f := database.TokenTransferQueryFactory.NewFilter(ctx) - switch transfers, _, err := or.database.Plugin.GetTokenTransfers(ctx, f.Eq("tx.id", id)); { + switch transfers, _, err := or.database.GetTokenTransfers(ctx, f.Eq("tx.id", id)); { case err != nil: return nil, err case len(transfers) == 0: @@ -172,7 +172,7 @@ func (or *orchestrator) GetTransactionStatus(ctx context.Context, ns, id string) updateStatus(result, core.OpStatusPending) } f := database.TokenApprovalQueryFactory.NewFilter(ctx) - switch approvals, _, err := or.database.Plugin.GetTokenApprovals(ctx, f.Eq("tx.id", id)); { + switch approvals, _, err := or.database.GetTokenApprovals(ctx, f.Eq("tx.id", id)); { case err != nil: return nil, err case len(approvals) == 0: From cd6c5dd6f82c1415a36f291aebf6e1907ededf54 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Mon, 6 Jun 2022 11:45:26 -0400 Subject: [PATCH 12/33] Complete orchestrator unit tests Signed-off-by: Andrew Richardson --- internal/orchestrator/orchestrator.go | 10 +- internal/orchestrator/orchestrator_test.go | 804 +++------------------ 2 files changed, 87 insertions(+), 727 deletions(-) diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index e523fb27ed..f60ceb8cfc 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -483,16 +483,12 @@ func (or *orchestrator) initComponents(ctx context.Context) (err error) { } } + or.syncasync.Init(or.events) + if or.networkmap == nil { or.networkmap, err = networkmap.NewNetworkMap(ctx, or.config.Multiparty.OrgName, or.config.Multiparty.OrgDesc, or.database, or.data, or.broadcast, or.dataexchange, or.identity, or.syncasync) - if err != nil { - return err - } } - - or.syncasync.Init(or.events) - - return nil + return err } func (or *orchestrator) SubmitNetworkAction(ctx context.Context, ns string, action *core.NetworkAction) error { diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index d00f9d8b9a..c3bc502d08 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -18,9 +18,11 @@ package orchestrator import ( "context" + "fmt" "testing" "github.com/hyperledger/firefly/internal/coreconfig" + "github.com/hyperledger/firefly/internal/identity" "github.com/hyperledger/firefly/mocks/admineventsmocks" "github.com/hyperledger/firefly/mocks/assetmocks" "github.com/hyperledger/firefly/mocks/batchmocks" @@ -43,8 +45,10 @@ import ( "github.com/hyperledger/firefly/mocks/sharedstoragemocks" "github.com/hyperledger/firefly/mocks/tokenmocks" "github.com/hyperledger/firefly/mocks/txcommonmocks" + "github.com/hyperledger/firefly/pkg/core" "github.com/hyperledger/firefly/pkg/tokens" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) const configDir = "../../test/data/config" @@ -108,6 +112,7 @@ func newTestOrchestrator() *testOrchestrator { orchestrator: orchestrator{ ctx: ctx, cancelCtx: cancel, + namespace: "ns", }, mdi: &databasemocks.Plugin{}, mdm: &datamocks.Manager{}, @@ -169,658 +174,101 @@ func newTestOrchestrator() *testOrchestrator { func TestNewOrchestrator(t *testing.T) { or := NewOrchestrator( "ns1", - Config{}, + Config{ + Tokens: map[string]TokensPlugin{"token": {Plugin: &tokenmocks.Plugin{}}}, + }, &metricsmocks.Manager{}, &admineventsmocks.Manager{}, ) assert.NotNil(t, or) } -/* -func TestBadDeprecatedDatabasePlugin(t *testing.T) { +func TestInitPluginsDatabaseFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - difactory.InitConfigDeprecated(deprecatedDatabaseConfig) - deprecatedDatabaseConfig.Set(coreconfig.PluginConfigType, "wrong") - or.databases = nil - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10122.*wrong", err) -} - -func TestBadDeprecatedDatabaseInitFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - difactory.InitConfigDeprecated(deprecatedDatabaseConfig) - deprecatedDatabaseConfig.AddKnownKey(coreconfig.PluginConfigType, "test") or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) ctx := context.Background() - err := or.initDeprecatedDatabasePlugin(ctx, or.mdi) - assert.EqualError(t, err, "pop") -} - -func TestDatabaseGetPlugins(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - difactory.InitConfig(databaseConfig) - config.Set("plugins.database", []fftypes.JSONObject{{}}) - databaseConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - databaseConfig.AddKnownKey(coreconfig.PluginConfigType, "postgres") - ctx := context.Background() - plugins, err := or.getDatabasePlugins(ctx) - assert.Equal(t, 1, len(plugins)) - assert.NoError(t, err) -} - -func TestDatabaseUnknownPlugin(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - difactory.InitConfig(databaseConfig) - config.Set("plugins.database", []fftypes.JSONObject{{}}) - databaseConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - databaseConfig.AddKnownKey(coreconfig.PluginConfigType, "unknown") - ctx := context.Background() - plugins, err := or.getDatabasePlugins(ctx) - assert.Nil(t, plugins) - assert.Error(t, err) -} - -func TestDatabaseGetPluginsNoName(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - difactory.InitConfig(databaseConfig) - config.Set("plugins.database", []fftypes.JSONObject{{}}) - databaseConfig.AddKnownKey(coreconfig.PluginConfigType, "postgres") - ctx := context.Background() - plugins, err := or.getDatabasePlugins(ctx) - assert.Nil(t, plugins) - assert.Error(t, err) -} - -func TestDatabaseGetPluginsBadName(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.databases = nil - difactory.InitConfig(databaseConfig) - config.Set("plugins.database", []fftypes.JSONObject{{}}) - databaseConfig.AddKnownKey(coreconfig.PluginConfigName, "wrong////") - databaseConfig.AddKnownKey(coreconfig.PluginConfigType, "postgres") - ctx := context.Background() err := or.initPlugins(ctx) - assert.Error(t, err) + assert.EqualError(t, err, "pop") } -func TestDeprecatedDatabaseInitPlugin(t *testing.T) { +func TestInitPluginsBlockchainFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - difactory.InitConfigDeprecated(deprecatedDatabaseConfig) - deprecatedDatabaseConfig.AddKnownKey(coreconfig.PluginConfigType, "postgres") or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - ctx := context.Background() - err := or.initDeprecatedDatabasePlugin(ctx, or.mdi) - assert.NoError(t, err) -} - -func TestDatabaseInitPlugins(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - difactory.InitConfig(databaseConfig) - config.Set("plugins.database", []fftypes.JSONObject{{}}) - databaseConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - databaseConfig.AddKnownKey(coreconfig.PluginConfigType, "postgres") - plugins := make([]database.Plugin, 1) - mdp := &databasemocks.Plugin{} - mdp.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - plugins[0] = mdp - ctx := context.Background() - err := or.initDatabasePlugins(ctx, plugins) - assert.NoError(t, err) -} - -func TestDatabaseInitPluginFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.databases = nil - difactory.InitConfig(databaseConfig) - config.Set("plugins.database", []fftypes.JSONObject{{}}) - databaseConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - databaseConfig.AddKnownKey(coreconfig.PluginConfigType, "sqlite3") - ctx := context.Background() - err := or.initPlugins(ctx) - assert.Regexp(t, "FF10138.*url", err) -} - -func TestDeprecatedDatabaseInitPluginFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.databases = nil - difactory.InitConfigDeprecated(deprecatedDatabaseConfig) - deprecatedDatabaseConfig.AddKnownKey(coreconfig.PluginConfigType, "sqlite3") + or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, or.mmi).Return(fmt.Errorf("pop")) ctx := context.Background() err := or.initPlugins(ctx) - assert.Regexp(t, "FF10138.*url", err) -} - -func TestIdentityPluginMissingType(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.database = or.mdi - or.identityPlugins = nil - iifactory.InitConfig(identityConfig) - identityConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - config.Set("plugins.identity", []fftypes.JSONObject{{}}) - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10386.*type", err) -} - -func TestIdentityPluginBadName(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.database = or.mdi - or.identityPlugins = nil - iifactory.InitConfig(identityConfig) - identityConfig.AddKnownKey(coreconfig.PluginConfigName, "wrong//") - identityConfig.AddKnownKey(coreconfig.PluginConfigType, "tbd") - config.Set("plugins.identity", []fftypes.JSONObject{{}}) - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF00140.*name", err) -} - -func TestIdentityPluginUnknownPlugin(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.database = or.mdi - or.identityPlugins = nil - iifactory.InitConfig(identityConfig) - identityConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - identityConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong") - config.Set("plugins.identity", []fftypes.JSONObject{{}}) - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10212.*wrong", err) -} - -func TestIdentityPlugin(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.database = or.mdi - or.identityPlugins = nil - iifactory.InitConfig(identityConfig) - identityConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - identityConfig.AddKnownKey(coreconfig.PluginConfigType, "onchain") - config.Set("plugins.identity", []fftypes.JSONObject{{}}) - or.mns.On("Init", mock.Anything, or.mdi).Return(nil) - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.NoError(t, err) -} - -func TestBadIdentityInitFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.blockchains = nil - config.Set("plugins.identity", []fftypes.JSONObject{{}}) - iifactory.InitConfig(identityConfig) - identityConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - identityConfig.AddKnownKey(coreconfig.PluginConfigType, "onchain") - plugins := make([]identity.Plugin, 1) - mii := &identitymocks.Plugin{} - mii.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - plugins[0] = mii - ctx := context.Background() - err := or.initIdentityPlugins(ctx, plugins) assert.EqualError(t, err, "pop") } -func TestBadDeprecatedBlockchainPlugin(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - deprecatedBlockchainConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong") - or.blockchains = nil - or.databases["database_0"] = or.mdi - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10110.*wrong", err) -} - -func TestDeprecatedBlockchainInitFail(t *testing.T) { +func TestInitPluginsDataexchangeNodesFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - bifactory.InitConfigDeprecated(deprecatedBlockchainConfig) - deprecatedBlockchainConfig.AddKnownKey(coreconfig.PluginConfigType, "ethereum") - or.blockchains = nil - or.databases["database_0"] = or.mdi - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10138.*url", err) -} - -func TestBlockchainGetPlugins(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - bifactory.InitConfig(blockchainConfig) - config.Set("plugins.blockchain", []fftypes.JSONObject{{}}) - blockchainConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - blockchainConfig.AddKnownKey(coreconfig.PluginConfigType, "ethereum") - ctx := context.Background() - plugins, err := or.getBlockchainPlugins(ctx) - assert.Equal(t, 1, len(plugins)) - assert.NoError(t, err) -} - -func TestBlockchainGetPluginsNoType(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - bifactory.InitConfig(blockchainConfig) - config.Set("plugins.blockchain", []fftypes.JSONObject{{}}) - blockchainConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - ctx := context.Background() - _, err := or.getBlockchainPlugins(ctx) - assert.Error(t, err) -} - -func TestBlockchainGetPluginsBadName(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - bifactory.InitConfig(blockchainConfig) - config.Set("plugins.blockchain", []fftypes.JSONObject{{}}) - blockchainConfig.AddKnownKey(coreconfig.PluginConfigName, "wrong/////////////") - blockchainConfig.AddKnownKey(coreconfig.PluginConfigType, "ethereum") - ctx := context.Background() - _, err := or.getBlockchainPlugins(ctx) - assert.Error(t, err) -} - -func TestBlockchainGetPluginsBadPlugin(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - bifactory.InitConfig(blockchainConfig) - config.Set("plugins.blockchain", []fftypes.JSONObject{{}}) - blockchainConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - blockchainConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong//") - or.blockchains = nil + or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("pop")) ctx := context.Background() err := or.initPlugins(ctx) - assert.Error(t, err) -} - -func TestBlockchainInitPlugins(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - bifactory.InitConfig(blockchainConfig) - config.Set("plugins.blockchain", []fftypes.JSONObject{{}}) - blockchainConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - blockchainConfig.AddKnownKey(coreconfig.PluginConfigType, "ethereum") - plugins := make([]blockchain.Plugin, 1) - mbp := &blockchainmocks.Plugin{} - mbp.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) - plugins[0] = mbp - ctx := context.Background() - err := or.initBlockchainPlugins(ctx, plugins) - assert.NoError(t, err) -} - -func TestDeprecatedBlockchainInitPlugin(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - bifactory.InitConfigDeprecated(deprecatedBlockchainConfig) - deprecatedBlockchainConfig.AddKnownKey(coreconfig.PluginConfigType, "ethereum") - or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) - ctx := context.Background() - err := or.initDeprecatedBlockchainPlugin(ctx, or.mbi) - assert.NoError(t, err) + assert.EqualError(t, err, "pop") } -func TestBlockchainInitPluginsFail(t *testing.T) { +func TestInitPluginsDataexchangeFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - bifactory.InitConfig(blockchainConfig) - config.Set("plugins.blockchain", []fftypes.JSONObject{{}}) - blockchainConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - blockchainConfig.AddKnownKey(coreconfig.PluginConfigType, "ethereum") - blockchainConfig.AddKnownKey("addressResolver.urlTemplate", "") - blockchainConfig.AddKnownKey("ethconnect.url", "") - or.blockchains = nil - + or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) + or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) ctx := context.Background() err := or.initPlugins(ctx) - assert.Regexp(t, "FF10138.*url", err) -} - -func TestBadSharedStoragePlugin(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - ssfactory.InitConfig(sharedstorageConfig) - sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong") - config.Set("plugins.sharedstorage", []fftypes.JSONObject{{}}) - or.sharedstoragePlugins = nil - ctx := context.Background() - plugins, err := or.getSharedStoragePlugins(ctx) - assert.Nil(t, plugins) - assert.Regexp(t, "FF10386.*Invalid", err) -} - -func TestBadSharedStoragePluginType(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.sharedstoragePlugins = nil - or.database = or.mdi - ssfactory.InitConfig(sharedstorageConfig) - sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigName, "sharedstorage") - sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong") - config.Set("plugins.sharedstorage", []fftypes.JSONObject{{}}) - - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10134.*wrong", err) -} - -func TestBadSharedStoragePluginName(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - ssfactory.InitConfig(sharedstorageConfig) - sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigName, "wrong////") - sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigType, "ipfs") - config.Set("plugins.sharedstorage", []fftypes.JSONObject{{}}) - or.sharedstoragePlugins = nil - ctx := context.Background() - plugins, err := or.getSharedStoragePlugins(ctx) - assert.Nil(t, plugins) - assert.Regexp(t, "FF00140.*name", err) -} - -func TestSharedStorageInitPlugins(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - ssfactory.InitConfig(sharedstorageConfig) - config.Set("plugins.sharedstorage", []fftypes.JSONObject{{}}) - sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigType, "ipfs") - plugins := make([]sharedstorage.Plugin, 1) - mss := &sharedstoragemocks.Plugin{} - mss.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - plugins[0] = mss - ctx := context.Background() - err := or.initSharedStoragePlugins(ctx, plugins) - assert.NoError(t, err) + assert.EqualError(t, err, "pop") } -func TestSharedStorageInitPluginsFail(t *testing.T) { +func TestInitPluginsSharedstorageFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.sharedstoragePlugins = nil - or.database = or.mdi - ssfactory.InitConfig(sharedstorageConfig) - config.Set("plugins.sharedstorage", []fftypes.JSONObject{{}}) - sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigType, "ipfs") + or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) + or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mps.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) ctx := context.Background() err := or.initPlugins(ctx) - assert.Regexp(t, "FF10138.*url", err) + assert.EqualError(t, err, "pop") } -func TestDeprecatedSharedStorageInitPlugin(t *testing.T) { +func TestInitPluginsTokensFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - ssfactory.InitConfigDeprecated(deprecatedSharedStorageConfig) - deprecatedSharedStorageConfig.AddKnownKey(coreconfig.PluginConfigType, "ipfs") + or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) + or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) or.mps.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - ctx := context.Background() - err := or.initDeprecatedSharedStoragePlugin(ctx, or.mps) - assert.NoError(t, err) -} - -func TestDeprecatedSharedStorageInitPluginFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.sharedstoragePlugins = nil - ssfactory.InitConfigDeprecated(deprecatedSharedStorageConfig) - deprecatedSharedStorageConfig.AddKnownKey(coreconfig.PluginConfigType, "ipfs") + or.mti.On("Init", mock.Anything, "token", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) ctx := context.Background() err := or.initPlugins(ctx) - assert.Regexp(t, "FF10138.*url", err) -} - -func TestBadDeprecatedSharedStoragePlugin(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - deprecatedSharedStorageConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong") - or.sharedstoragePlugins = nil - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10134.*Unknown", err) -} - -func TestBadDataExchangePlugin(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - dxfactory.InitConfig(dataexchangeConfig) - dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong//") - config.Set("plugins.dataexchange", []fftypes.JSONObject{{}}) - or.database = or.mdi - or.dataexchangePlugins = nil - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10213.*wrong", err) -} - -func TestDataExchangePluginBadName(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - dxfactory.InitConfig(dataexchangeConfig) - dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigName, "wrong//") - dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigType, "ffdx") - config.Set("plugins.dataexchange", []fftypes.JSONObject{{}}) - or.database = or.mdi - or.dataexchangePlugins = nil - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF00140.*name", err) -} - -func TestDataExchangePluginMissingName(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - dxfactory.InitConfig(dataexchangeConfig) - dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigType, "ffdx") - config.Set("plugins.dataexchange", []fftypes.JSONObject{{}}) - or.database = or.mdi - or.dataexchangePlugins = nil - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10386.*name", err) -} - -func TestBadDataExchangeInitFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - dxfactory.InitConfig(dataexchangeConfig) - dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigType, "ffdx") - config.Set("plugins.dataexchange", []fftypes.JSONObject{{}}) - or.database = or.mdi - or.dataexchangePlugins = nil - or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{}, nil, nil) - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10138.*url", err) -} - -func TestDeprecatedBadDataExchangeInitFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - dxfactory.InitConfigDeprecated(deprecatedDataexchangeConfig) - deprecatedDataexchangeConfig.AddKnownKey(coreconfig.PluginConfigType, "ffdx") - or.database = or.mdi - or.dataexchangePlugins = nil - or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{}, nil, nil) - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10138.*url", err) -} - -func TestDeprecatedDataExchangeInit(t *testing.T) { - or := newTestOrchestrator() - dxfactory.InitConfigDeprecated(deprecatedDataexchangeConfig) - deprecatedDataexchangeConfig.AddKnownKey(coreconfig.PluginConfigType, "ffdx") - deprecatedDataexchangeConfig.AddKnownKey(coreconfig.PluginConfigType, "ffdx") - deprecatedDataexchangeConfig.AddKnownKey("ffdx.url", "https://test") - or.database = or.mdi - or.dataexchangePlugins = nil - or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{}, nil, nil) - ctx := context.Background() - err := or.initDataExchange(ctx) - assert.NoError(t, err) -} - -func TestDeprecatedBadDataExchangePlugin(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - dxfactory.InitConfigDeprecated(deprecatedDataexchangeConfig) - deprecatedDataexchangeConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong//") - or.database = or.mdi - or.dataexchangePlugins = nil - or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{}, nil, nil) - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10213.*wrong", err) -} - -func TestTokensMissingName(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - tifactory.InitConfig(tokensConfig) - tokensConfig.AddKnownKey(coreconfig.PluginConfigType, "fftokens") - config.Set("plugins.tokens", []fftypes.JSONObject{{}}) - or.database = or.mdi - or.tokens = nil - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10386.*type", err) -} - -func TestTokensBadName(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - tifactory.InitConfig(tokensConfig) - tokensConfig.AddKnownKey(coreconfig.PluginConfigName, "/////////////") - tokensConfig.AddKnownKey(coreconfig.PluginConfigType, "fftokens") - config.Set("plugins.tokens", []fftypes.JSONObject{{}}) - or.database = or.mdi - or.tokens = nil - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF00140.*name", err) -} - -func TestBadTokensPlugin(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - tifactory.InitConfig(tokensConfig) - tokensConfig.AddKnownKey(coreconfig.PluginConfigName, "erc20_erc721") - tokensConfig.AddKnownKey(coreconfig.PluginConfigType, "fftokens") - config.Set("plugins.tokens", []fftypes.JSONObject{{}}) - or.database = or.mdi - or.tokens = nil - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Error(t, err) -} - -func TestDuplicatePluginNames(t *testing.T) { - or := newTestOrchestrator() - or.pluginNames["duplicate"] = true - tifactory.InitConfig(tokensConfig) - utConfig := config.RootSection("test") - utConfig.AddKnownKey(coreconfig.PluginConfigName, "duplicate") - utConfig.AddKnownKey(coreconfig.PluginConfigType, "fftokens") - ctx := context.Background() - err := or.validatePluginConfig(ctx, utConfig, "test") - assert.Regexp(t, "FF10395", err) -} - -func TestGoodTokensPlugin(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - tifactory.InitConfig(tokensConfig) - tokensConfig.AddKnownKey(coreconfig.PluginConfigName, "erc20_erc721") - tokensConfig.AddKnownKey(coreconfig.PluginConfigType, "fftokens") - tokensConfig.AddKnownKey("fftokens.url", "test") - config.Set("plugins.tokens", []fftypes.JSONObject{{}}) - or.database = or.mdi - or.tokens = nil - or.mns.On("Init", mock.Anything, or.mdi).Return(nil) - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.NoError(t, err) -} - -func TestBadDeprecatedTokensPluginNoName(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - tifactory.InitConfigDeprecated(deprecatedTokensConfig) - deprecatedTokensConfig.AddKnownKey(coreconfig.PluginConfigName) - deprecatedTokensConfig.AddKnownKey(tokens.TokensConfigPlugin, "wrong") - config.Set("tokens", []fftypes.JSONObject{{}}) - or.database = or.mdi - or.tokens = nil - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10273", err) -} - -func TestBadDeprecatedTokensPluginInvalidName(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - tifactory.InitConfigDeprecated(deprecatedTokensConfig) - deprecatedTokensConfig.AddKnownKey(coreconfig.PluginConfigName, "!wrong") - deprecatedTokensConfig.AddKnownKey(tokens.TokensConfigPlugin, "text") - config.Set("tokens", []fftypes.JSONObject{{}}) - or.database = or.mdi - or.tokens = nil - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF00140.*'name'", err) -} - -func TestBadDeprecatedTokensPluginNoType(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - tifactory.InitConfigDeprecated(deprecatedTokensConfig) - deprecatedTokensConfig.AddKnownKey(coreconfig.PluginConfigName, "text") - deprecatedTokensConfig.AddKnownKey(tokens.TokensConfigPlugin) - config.Set("tokens", []fftypes.JSONObject{{}}) - or.database = or.mdi - or.tokens = nil - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.Regexp(t, "FF10272", err) + assert.EqualError(t, err, "pop") } -func TestGoodDeprecatedTokensPlugin(t *testing.T) { +func TestInitAllPluginsOK(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - deprecatedTokensConfig = config.RootArray("tokens") - tifactory.InitConfigDeprecated(deprecatedTokensConfig) - deprecatedTokensConfig.AddKnownKey(coreconfig.PluginConfigName, "test") - deprecatedTokensConfig.AddKnownKey(tokens.TokensConfigPlugin, "fftokens") - deprecatedTokensConfig.AddKnownKey(ffresty.HTTPConfigURL, "test") - config.Set("tokens", []fftypes.JSONObject{{}}) - or.database = or.mdi - or.tokens = nil - or.mns.On("Init", mock.Anything, or.mdi).Return(nil) - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) + or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) + or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mps.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mti.On("Init", mock.Anything, "token", mock.Anything, mock.Anything).Return(nil) + err := or.Init(or.ctx, or.cancelCtx) assert.NoError(t, err) } func TestInitMessagingComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.messaging = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -829,7 +277,7 @@ func TestInitMessagingComponentFail(t *testing.T) { func TestInitEventsComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.events = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -838,7 +286,7 @@ func TestInitEventsComponentFail(t *testing.T) { func TestInitNetworkMapComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.networkmap = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -847,7 +295,7 @@ func TestInitNetworkMapComponentFail(t *testing.T) { func TestInitOperationComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.operations = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -856,24 +304,16 @@ func TestInitOperationComponentFail(t *testing.T) { func TestInitSharedStorageDownloadComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.sharedDownload = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) } -func TestInitAdminEventsInit(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.adminEvents = nil - err := or.initPlugins(context.Background()) - assert.NoError(t, err) -} - func TestInitBatchComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.batch = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -882,7 +322,7 @@ func TestInitBatchComponentFail(t *testing.T) { func TestInitBroadcastComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.broadcast = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -891,7 +331,7 @@ func TestInitBroadcastComponentFail(t *testing.T) { func TestInitDataComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.data = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -900,7 +340,7 @@ func TestInitDataComponentFail(t *testing.T) { func TestInitIdentityComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.identity = nil or.txHelper = nil err := or.initComponents(context.Background()) @@ -910,7 +350,7 @@ func TestInitIdentityComponentFail(t *testing.T) { func TestInitAssetsComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.assets = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -919,7 +359,7 @@ func TestInitAssetsComponentFail(t *testing.T) { func TestInitContractsComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.contracts = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -928,7 +368,7 @@ func TestInitContractsComponentFail(t *testing.T) { func TestInitDefinitionsComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.definitions = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -937,7 +377,7 @@ func TestInitDefinitionsComponentFail(t *testing.T) { func TestInitBatchPinComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.batchpin = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -946,25 +386,20 @@ func TestInitBatchPinComponentFail(t *testing.T) { func TestInitOperationsComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.databases = nil + or.database = nil or.operations = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) } -func TestInitNamespaceComponentFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.namespace = nil - err := or.initNamespaces(context.Background()) - assert.Regexp(t, "FF10166", err) -} - func TestStartBatchFail(t *testing.T) { coreconfig.Reset() or := newTestOrchestrator() defer or.cleanup(t) - or.mmi.On("Start").Return(nil) + or.mdi.On("GetNamespace", mock.Anything, "ns").Return(nil, nil) + or.mdi.On("UpsertNamespace", mock.Anything, mock.Anything, true).Return(nil) + or.mbi.On("ConfigureContract", mock.Anything, mock.Anything).Return(nil) + or.mbi.On("Start").Return(nil) or.mba.On("Start").Return(fmt.Errorf("pop")) err := or.Start() assert.EqualError(t, err, "pop") @@ -974,8 +409,8 @@ func TestStartTokensFail(t *testing.T) { coreconfig.Reset() or := newTestOrchestrator() defer or.cleanup(t) - or.database = or.mdi - or.mdi.On("GetNamespace", mock.Anything, "ff_system").Return(&core.Namespace{}, nil) + or.mdi.On("GetNamespace", mock.Anything, "ns").Return(nil, nil) + or.mdi.On("UpsertNamespace", mock.Anything, mock.Anything, true).Return(nil) or.mbi.On("ConfigureContract", mock.Anything, &core.FireFlyContracts{}).Return(nil) or.mbi.On("Start").Return(nil) or.mba.On("Start").Return(nil) @@ -984,9 +419,7 @@ func TestStartTokensFail(t *testing.T) { or.mpm.On("Start").Return(nil) or.msd.On("Start").Return(nil) or.mom.On("Start").Return(nil) - or.mmi.On("Start").Return(nil) or.mti.On("Start").Return(fmt.Errorf("pop")) - or.mdi.On("UpsertNamespace", mock.Anything, mock.Anything, true).Return(nil) err := or.Start() assert.EqualError(t, err, "pop") } @@ -995,12 +428,9 @@ func TestStartBlockchainsFail(t *testing.T) { coreconfig.Reset() or := newTestOrchestrator() defer or.cleanup(t) - or.database = or.mdi - or.mdi.On("GetNamespace", mock.Anything, "ff_system").Return(&core.Namespace{}, nil) + or.mdi.On("GetNamespace", mock.Anything, "ns").Return(nil, nil) or.mbi.On("ConfigureContract", mock.Anything, &core.FireFlyContracts{}).Return(nil) or.mbi.On("Start").Return(fmt.Errorf("pop")) - or.mba.On("Start").Return(nil) - or.mmi.On("Start").Return(nil) err := or.Start() assert.EqualError(t, err, "pop") } @@ -1009,11 +439,8 @@ func TestStartBlockchainsConfigureFail(t *testing.T) { coreconfig.Reset() or := newTestOrchestrator() defer or.cleanup(t) - or.database = or.mdi - or.mdi.On("GetNamespace", mock.Anything, "ff_system").Return(&core.Namespace{}, nil) + or.mdi.On("GetNamespace", mock.Anything, "ns").Return(nil, nil) or.mbi.On("ConfigureContract", mock.Anything, &core.FireFlyContracts{}).Return(fmt.Errorf("pop")) - or.mba.On("Start").Return(nil) - or.mmi.On("Start").Return(nil) err := or.Start() assert.EqualError(t, err, "pop") } @@ -1022,8 +449,8 @@ func TestStartStopOk(t *testing.T) { coreconfig.Reset() or := newTestOrchestrator() defer or.cleanup(t) - or.database = or.mdi - or.mdi.On("GetNamespace", mock.Anything, "ff_system").Return(&core.Namespace{}, nil) + or.mdi.On("GetNamespace", mock.Anything, "ns").Return(nil, nil) + or.mdi.On("UpsertNamespace", mock.Anything, mock.Anything, true).Return(nil) or.mbi.On("ConfigureContract", mock.Anything, &core.FireFlyContracts{}).Return(nil) or.mbi.On("Start").Return(nil) or.mba.On("Start").Return(nil) @@ -1031,7 +458,6 @@ func TestStartStopOk(t *testing.T) { or.mbm.On("Start").Return(nil) or.mpm.On("Start").Return(nil) or.mti.On("Start").Return(nil) - or.mmi.On("Start").Return(nil) or.msd.On("Start").Return(nil) or.mom.On("Start").Return(nil) or.mba.On("WaitStop").Return(nil) @@ -1039,49 +465,21 @@ func TestStartStopOk(t *testing.T) { or.mdm.On("WaitStop").Return(nil) or.msd.On("WaitStop").Return(nil) or.mom.On("WaitStop").Return(nil) - or.mae.On("WaitStop").Return(nil) - or.mdi.On("UpsertNamespace", mock.Anything, mock.Anything, true).Return(nil) err := or.Start() assert.NoError(t, err) or.WaitStop() or.WaitStop() // swallows dups } -func TestInitOK(t *testing.T) { +func TestGetComponents(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = or.mdi - err := config.ReadConfig("core", configDir+"/firefly.core.yaml") - assert.NoError(t, err) - or.mns.On("Init", mock.Anything, or.mdi).Return(nil) - ctx, cancelCtx := context.WithCancel(context.Background()) - err = or.Init(ctx, cancelCtx) - assert.NoError(t, err) - assert.Equal(t, or.mbm, or.Broadcast()) - assert.Equal(t, or.mpm, or.PrivateMessaging()) - assert.Equal(t, or.mem, or.Events()) - assert.Equal(t, or.mba, or.BatchManager()) - assert.Equal(t, or.mnm, or.NetworkMap()) - assert.Equal(t, or.mdm, or.Data()) - assert.Equal(t, or.mam, or.Assets()) - assert.Equal(t, or.mcm, or.Contracts()) - assert.Equal(t, or.mmi, or.Metrics()) - assert.Equal(t, or.mom, or.Operations()) - assert.Equal(t, or.mae, or.AdminEvents()) -} + or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) -func TestInitOKWithMetrics(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.metrics = nil - or.database = or.mdi - err := config.ReadConfig("core", configDir+"/firefly.core.yaml") - assert.NoError(t, err) - or.mns.On("Init", mock.Anything, or.mdi).Return(nil) ctx, cancelCtx := context.WithCancel(context.Background()) - err = or.Init(ctx, cancelCtx) - assert.NoError(t, err) + err := or.Init(ctx, cancelCtx) + assert.EqualError(t, err, "pop") assert.Equal(t, or.mbm, or.Broadcast()) assert.Equal(t, or.mpm, or.PrivateMessaging()) @@ -1091,53 +489,13 @@ func TestInitOKWithMetrics(t *testing.T) { assert.Equal(t, or.mdm, or.Data()) assert.Equal(t, or.mam, or.Assets()) assert.Equal(t, or.mcm, or.Contracts()) + assert.Equal(t, or.mmi, or.Metrics()) assert.Equal(t, or.mom, or.Operations()) - assert.Equal(t, or.mae, or.AdminEvents()) -} - -func TestInitNamespaceFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.database = or.mdi - err := config.ReadConfig("core", configDir+"/firefly.core.yaml") - assert.NoError(t, err) - or.mns.On("Init", mock.Anything, or.mdi).Return(fmt.Errorf("pop")) - ctx, cancelCtx := context.WithCancel(context.Background()) - err = or.Init(ctx, cancelCtx) - assert.EqualError(t, err, "pop") -} - -func TestInitDataExchangeGetNodesFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.database = or.mdi - - or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("pop")) - - err := or.initDataExchange(or.ctx) - assert.EqualError(t, err, "pop") -} - -func TestInitDataExchangeWithNodes(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.database = or.mdi - dxfactory.InitConfig(dataexchangeConfig) - dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") - dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigType, "ffdx") - dataexchangeConfig.AddKnownKey("ffdx.url", "https://test") - config.Set("plugins.dataexchange", []fftypes.JSONObject{{}}) - - or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) - - err := or.initDataExchange(or.ctx) - assert.NoError(t, err) } func TestNetworkAction(t *testing.T) { or := newTestOrchestrator() - or.blockchain = or.mbi - or.mim.On("NormalizeSigningKey", context.Background(), "ff_system", "", identitymanager.KeyNormalizationBlockchainPlugin).Return("0x123", nil) + or.mim.On("NormalizeSigningKey", context.Background(), "ff_system", "", identity.KeyNormalizationBlockchainPlugin).Return("0x123", nil) or.mbi.On("SubmitNetworkAction", context.Background(), mock.Anything, "0x123", core.NetworkActionTerminate).Return(nil) err := or.SubmitNetworkAction(context.Background(), "ff_system", &core.NetworkAction{Type: core.NetworkActionTerminate}) assert.NoError(t, err) @@ -1145,15 +503,21 @@ func TestNetworkAction(t *testing.T) { func TestNetworkActionBadKey(t *testing.T) { or := newTestOrchestrator() - or.mim.On("NormalizeSigningKey", context.Background(), "ff_system", "", identitymanager.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) + or.mim.On("NormalizeSigningKey", context.Background(), "ff_system", "", identity.KeyNormalizationBlockchainPlugin).Return("", fmt.Errorf("pop")) err := or.SubmitNetworkAction(context.Background(), "ff_system", &core.NetworkAction{Type: core.NetworkActionTerminate}) assert.EqualError(t, err, "pop") } func TestNetworkActionBadType(t *testing.T) { or := newTestOrchestrator() - or.mim.On("NormalizeSigningKey", context.Background(), "ff_system", "", identitymanager.KeyNormalizationBlockchainPlugin).Return("0x123", nil) + or.mim.On("NormalizeSigningKey", context.Background(), "ff_system", "", identity.KeyNormalizationBlockchainPlugin).Return("0x123", nil) err := or.SubmitNetworkAction(context.Background(), "ff_system", &core.NetworkAction{Type: "bad"}) assert.Regexp(t, "FF10397", err) } -*/ + +func TestNetworkActionBadNamespace(t *testing.T) { + or := newTestOrchestrator() + or.mim.On("NormalizeSigningKey", context.Background(), "ns", "", identity.KeyNormalizationBlockchainPlugin).Return("0x123", nil) + err := or.SubmitNetworkAction(context.Background(), "ns", &core.NetworkAction{Type: core.NetworkActionTerminate}) + assert.Regexp(t, "FF10399", err) +} From 0f3facb3b9108bbcc4d72de3c5d7d3500d769aba Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Mon, 6 Jun 2022 15:56:19 -0400 Subject: [PATCH 13/33] Complete namespace manager tests Signed-off-by: Andrew Richardson --- internal/namespace/manager.go | 53 +- internal/namespace/manager_test.go | 933 +++++++++++++++++++++-------- 2 files changed, 711 insertions(+), 275 deletions(-) diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index 9b0259211b..36a699a349 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -83,6 +83,7 @@ type namespaceManager struct { tokens map[string]orchestrator.TokensPlugin adminEvents adminevents.Manager namespaces map[string]*namespace + utOrchestrator orchestrator.Orchestrator metricsEnabled bool } @@ -114,19 +115,21 @@ func (nm *namespaceManager) Init(ctx context.Context, cancelCtx context.CancelFu nm.ctx = ctx nm.cancelCtx = cancelCtx - err = nm.getPlugins(ctx) + err = nm.loadPlugins(ctx) if err != nil { return err } - nsConfig := buildNamespaceMap(ctx) - if err = nm.initNamespaces(ctx, nsConfig); err != nil { + if err = nm.loadNamespaces(ctx); err != nil { return err } // Start an orchestrator per namespace for name, ns := range nm.namespaces { - or := orchestrator.NewOrchestrator(name, ns.config, nm.metrics, nm.adminEvents) + or := nm.utOrchestrator + if or == nil { + or = orchestrator.NewOrchestrator(name, ns.config, nm.metrics, nm.adminEvents) + } if err = or.Init(ctx, cancelCtx); err != nil { return err } @@ -155,11 +158,7 @@ func (nm *namespaceManager) WaitStop() { nm.adminEvents.WaitStop() } -func (nm *namespaceManager) AdminEvents() adminevents.Manager { - return nm.adminEvents -} - -func (nm *namespaceManager) getPlugins(ctx context.Context) (err error) { +func (nm *namespaceManager) loadPlugins(ctx context.Context) (err error) { nm.pluginNames = make(map[string]bool) if nm.metrics == nil { nm.metrics = metrics.NewMetricsManager(ctx) @@ -248,7 +247,7 @@ func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[s deprecatedConfig := deprecatedTokensConfig.ArrayEntry(i) name := deprecatedConfig.GetString(coreconfig.PluginConfigName) pluginType := deprecatedConfig.GetString(tokens.TokensConfigPlugin) - if name == "" { + if name == "" || pluginType == "" { return nil, i18n.NewError(ctx, coremsgs.MsgMissingTokensPluginConfig) } if err = core.ValidateFFNameField(ctx, name, "name"); err != nil { @@ -294,7 +293,7 @@ func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map } // check for deprecated config - if len(nm.databases) == 0 { + if len(plugins) == 0 { pluginType := deprecatedDatabaseConfig.GetString(coreconfig.PluginConfigType) plugin, err := difactory.GetPlugin(ctx, deprecatedDatabaseConfig.GetString(coreconfig.PluginConfigType)) if err != nil { @@ -479,12 +478,12 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin return plugins, err } -func buildNamespaceMap(ctx context.Context) map[string]config.Section { - conf := namespacePredefined - namespaces := make(map[string]config.Section, conf.ArraySize()) - size := conf.ArraySize() +func (nm *namespaceManager) loadNamespaces(ctx context.Context) (err error) { + defaultNS := config.GetString(coreconfig.NamespacesDefault) + size := namespacePredefined.ArraySize() + namespaces := make(map[string]config.Section, size) for i := 0; i < size; i++ { - nsConfig := conf.ArrayEntry(i) + nsConfig := namespacePredefined.ArrayEntry(i) name := nsConfig.GetString(coreconfig.NamespaceName) if name != "" { if _, ok := namespaces[name]; ok { @@ -493,15 +492,11 @@ func buildNamespaceMap(ctx context.Context) map[string]config.Section { namespaces[name] = nsConfig } } - return namespaces -} -func (nm *namespaceManager) initNamespaces(ctx context.Context, nsConfig map[string]config.Section) (err error) { - defaultNS := config.GetString(coreconfig.NamespacesDefault) i := 0 foundDefault := false - for name, nsObject := range nsConfig { - if err := nm.buildAndValidateNamespaces(ctx, name, i, nsObject); err != nil { + for name, nsObject := range namespaces { + if err := nm.loadNamespace(ctx, name, i, nsObject); err != nil { return err } i++ @@ -513,7 +508,7 @@ func (nm *namespaceManager) initNamespaces(ctx context.Context, nsConfig map[str return err } -func (nm *namespaceManager) buildAndValidateNamespaces(ctx context.Context, name string, index int, conf config.Section) error { +func (nm *namespaceManager) loadNamespace(ctx context.Context, name string, index int, conf config.Section) error { if err := core.ValidateFFNameField(ctx, name, fmt.Sprintf("namespaces.predefined[%d].name", index)); err != nil { return err } @@ -541,8 +536,9 @@ func (nm *namespaceManager) buildAndValidateNamespaces(ctx context.Context, name } // If no plugins are listed under this namespace, use all defined plugins by default + pluginsRaw := conf.Get(coreconfig.NamespacePlugins) plugins := conf.GetStringSlice(coreconfig.NamespacePlugins) - if len(plugins) == 0 { + if pluginsRaw == nil { for plugin := range nm.blockchains { plugins = append(plugins, plugin) } @@ -559,6 +555,10 @@ func (nm *namespaceManager) buildAndValidateNamespaces(ctx context.Context, name plugins = append(plugins, plugin) } + for plugin := range nm.identities { + plugins = append(plugins, plugin) + } + for plugin := range nm.tokens { plugins = append(plugins, plugin) } @@ -687,6 +687,10 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name stri return nil } +func (nm *namespaceManager) AdminEvents() adminevents.Manager { + return nm.adminEvents +} + func (nm *namespaceManager) Orchestrator(ns string) orchestrator.Orchestrator { if namespace, ok := nm.namespaces[ns]; ok { return namespace.orchestrator @@ -695,5 +699,6 @@ func (nm *namespaceManager) Orchestrator(ns string) orchestrator.Orchestrator { } func (nm *namespaceManager) GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) { + // TODO: implement return nil, nil, nil } diff --git a/internal/namespace/manager_test.go b/internal/namespace/manager_test.go index e1c3178f69..ffb62b23dc 100644 --- a/internal/namespace/manager_test.go +++ b/internal/namespace/manager_test.go @@ -17,46 +17,63 @@ package namespace import ( + "context" + "fmt" + "strings" "testing" + "github.com/hyperledger/firefly-common/pkg/config" + "github.com/hyperledger/firefly-common/pkg/fftypes" + "github.com/hyperledger/firefly/internal/blockchain/bifactory" "github.com/hyperledger/firefly/internal/coreconfig" + "github.com/hyperledger/firefly/internal/database/difactory" + "github.com/hyperledger/firefly/internal/dataexchange/dxfactory" + "github.com/hyperledger/firefly/internal/identity/iifactory" "github.com/hyperledger/firefly/internal/orchestrator" + "github.com/hyperledger/firefly/internal/sharedstorage/ssfactory" + "github.com/hyperledger/firefly/internal/tokens/tifactory" + "github.com/hyperledger/firefly/mocks/admineventsmocks" "github.com/hyperledger/firefly/mocks/blockchainmocks" "github.com/hyperledger/firefly/mocks/databasemocks" "github.com/hyperledger/firefly/mocks/dataexchangemocks" + "github.com/hyperledger/firefly/mocks/identitymocks" + "github.com/hyperledger/firefly/mocks/metricsmocks" + "github.com/hyperledger/firefly/mocks/orchestratormocks" "github.com/hyperledger/firefly/mocks/sharedstoragemocks" "github.com/hyperledger/firefly/mocks/tokenmocks" + "github.com/hyperledger/firefly/pkg/database" + "github.com/hyperledger/firefly/pkg/tokens" + "github.com/spf13/viper" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) type testNamespaceManager struct { namespaceManager - mdi *databasemocks.Plugin - mbi *blockchainmocks.Plugin - mps *sharedstoragemocks.Plugin - mdx *dataexchangemocks.Plugin - mti *tokenmocks.Plugin + mmi *metricsmocks.Manager + mae *admineventsmocks.Manager } func (nm *testNamespaceManager) cleanup(t *testing.T) { - nm.mdi.AssertExpectations(t) } func newTestNamespaceManager(resetConfig bool) *testNamespaceManager { if resetConfig { coreconfig.Reset() InitConfig(true) + namespaceConfig.AddKnownKey("predefined.0.multiparty.enabled", true) } nm := &testNamespaceManager{ - mdi: &databasemocks.Plugin{}, + mmi: &metricsmocks.Manager{}, + mae: &admineventsmocks.Manager{}, namespaceManager: namespaceManager{ + namespaces: make(map[string]*namespace), + pluginNames: make(map[string]bool), blockchains: map[string]orchestrator.BlockchainPlugin{ "ethereum": {Plugin: &blockchainmocks.Plugin{}}, - "fabric": {Plugin: &blockchainmocks.Plugin{}}, }, databases: map[string]orchestrator.DatabasePlugin{ "postgres": {Plugin: &databasemocks.Plugin{}}, - "sqlite3": {Plugin: &databasemocks.Plugin{}}, }, dataexchanges: map[string]orchestrator.DataexchangePlugin{ "ffdx": {Plugin: &dataexchangemocks.Plugin{}}, @@ -64,11 +81,16 @@ func newTestNamespaceManager(resetConfig bool) *testNamespaceManager { sharedstorages: map[string]orchestrator.SharedStoragePlugin{ "ipfs": {Plugin: &sharedstoragemocks.Plugin{}}, }, + identities: map[string]orchestrator.IdentityPlugin{ + "tbd": {Plugin: &identitymocks.Plugin{}}, + }, tokens: map[string]orchestrator.TokensPlugin{ "erc721": {Plugin: &tokenmocks.Plugin{}}, }, }, } + nm.namespaceManager.metrics = nm.mmi + nm.namespaceManager.adminEvents = nm.mae return nm } @@ -77,318 +99,623 @@ func TestNewNamespaceManager(t *testing.T) { assert.NotNil(t, nm) } -/* func TestInit(t *testing.T) { - coreconfig.Reset() - nm := newTestNamespaceManager(false) + nm := newTestNamespaceManager(true) defer nm.cleanup(t) - nm.Init(context.Background(), nm.mdi) + mo := &orchestratormocks.Orchestrator{} + mo.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.utOrchestrator = mo + + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.NoError(t, err) + + assert.Equal(t, mo, nm.Orchestrator("default")) + assert.Nil(t, nm.Orchestrator("unknown")) } -func TestInitNamespacesBadName(t *testing.T) { - coreconfig.Reset() - namespaceConfig.AddKnownKey("predefined.0."+coreconfig.NamespaceName, "!Badness") - nm := newTestNamespaceManager(false) +func TestInitFail(t *testing.T) { + nm := newTestNamespaceManager(true) defer nm.cleanup(t) - utTestConfig := config.RootSection("test") + mdi := nm.databases["postgres"].Plugin.(*databasemocks.Plugin) + mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "!Badness") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "test") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, true) - utTestConfig.AddKnownKey(coreconfig.NamespaceDescription, "test description") - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres", "ffdx", "ipfs", "erc721"}) - nm.nsConfig = map[string]config.Section{"!Badness": utTestConfig} + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.EqualError(t, err, "pop") - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF00140", err) + mdi.AssertExpectations(t) } -func TestInitNamespacesReservedName(t *testing.T) { - coreconfig.Reset() - nm := newTestNamespaceManager(false) +func TestDeprecatedDatabasePlugin(t *testing.T) { + nm := newTestNamespaceManager(true) defer nm.cleanup(t) + difactory.InitConfigDeprecated(deprecatedDatabaseConfig) + deprecatedDatabaseConfig.Set(coreconfig.PluginConfigType, "postgres") + plugins, err := nm.getDatabasePlugins(context.Background()) + assert.Equal(t, 1, len(plugins)) + assert.NoError(t, err) +} - utTestConfig := config.RootSection("test") +func TestDeprecatedDatabasePluginBadType(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + difactory.InitConfigDeprecated(deprecatedDatabaseConfig) + deprecatedDatabaseConfig.Set(coreconfig.PluginConfigType, "wrong") + _, err := nm.getDatabasePlugins(context.Background()) + assert.Regexp(t, "FF10122.*wrong", err) +} - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "ff_system") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "test") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, true) - utTestConfig.AddKnownKey(coreconfig.NamespaceDescription, "test description") - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres", "ffdx", "ipfs", "erc721"}) - nm.nsConfig = map[string]config.Section{"ff_system": utTestConfig} +func TestDatabasePlugin(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + difactory.InitConfig(databaseConfig) + config.Set("plugins.database", []fftypes.JSONObject{{}}) + databaseConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + databaseConfig.AddKnownKey(coreconfig.PluginConfigType, "postgres") + plugins, err := nm.getDatabasePlugins(context.Background()) + assert.Equal(t, 1, len(plugins)) + assert.NoError(t, err) +} - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10388", err) +func TestDatabasePluginBadType(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + difactory.InitConfig(databaseConfig) + config.Set("plugins.database", []fftypes.JSONObject{{}}) + databaseConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + databaseConfig.AddKnownKey(coreconfig.PluginConfigType, "unknown") + plugins, err := nm.getDatabasePlugins(context.Background()) + assert.Nil(t, plugins) + assert.Error(t, err) } -func TestInitNamespacesGetFail(t *testing.T) { +func TestDatabasePluginBadName(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) + nm.databases = nil + difactory.InitConfig(databaseConfig) + config.Set("plugins.database", []fftypes.JSONObject{{}}) + databaseConfig.AddKnownKey(coreconfig.PluginConfigName, "wrong////") + databaseConfig.AddKnownKey(coreconfig.PluginConfigType, "postgres") + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.Error(t, err) +} - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, true) - utTestConfig.AddKnownKey(coreconfig.NamespaceDescription, "test description") - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres", "ffdx", "ipfs", "erc721"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} +func TestIdentityPluginBadName(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + iifactory.InitConfig(identityConfig) + identityConfig.AddKnownKey(coreconfig.PluginConfigName, "wrong//") + identityConfig.AddKnownKey(coreconfig.PluginConfigType, "tbd") + config.Set("plugins.identity", []fftypes.JSONObject{{}}) + _, err := nm.getIdentityPlugins(context.Background()) + assert.Regexp(t, "FF00140.*name", err) +} - nm.mdi.On("GetNamespace", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("pop")) - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "pop", err) +func TestIdentityPluginBadType(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + iifactory.InitConfig(identityConfig) + identityConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + identityConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong") + config.Set("plugins.identity", []fftypes.JSONObject{{}}) + _, err := nm.getIdentityPlugins(context.Background()) + assert.Regexp(t, "FF10212.*wrong", err) } -func TestInitNamespacesUpsertFail(t *testing.T) { +func TestIdentityPluginNoType(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) + nm.identities = nil + iifactory.InitConfig(identityConfig) + identityConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + config.Set("plugins.identity", []fftypes.JSONObject{{}}) + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.Regexp(t, "FF10386.*type", err) +} - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, true) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres", "ffdx", "ipfs", "erc721"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} +func TestIdentityPlugin(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + iifactory.InitConfig(identityConfig) + identityConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + identityConfig.AddKnownKey(coreconfig.PluginConfigType, "onchain") + config.Set("plugins.identity", []fftypes.JSONObject{{}}) + plugins, err := nm.getIdentityPlugins(context.Background()) + assert.NoError(t, err) + assert.Equal(t, 1, len(plugins)) +} - nm.mdi.On("GetNamespace", mock.Anything, mock.Anything).Return(nil, nil) - nm.mdi.On("UpsertNamespace", mock.Anything, mock.Anything, true).Return(fmt.Errorf("pop")) - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "pop", err) +func TestDeprecatedBlockchainPlugin(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + bifactory.InitConfigDeprecated(deprecatedBlockchainConfig) + deprecatedBlockchainConfig.Set(coreconfig.PluginConfigType, "ethereum") + plugins, err := nm.getBlockchainPlugins(context.Background()) + assert.Equal(t, 1, len(plugins)) + assert.NoError(t, err) } -func TestInitNamespacesMultipartyUnknownPlugin(t *testing.T) { +func TestDeprecatedBlockchainPluginBadType(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) + deprecatedBlockchainConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong") + _, err := nm.getBlockchainPlugins(context.Background()) + assert.Regexp(t, "FF10110.*wrong", err) +} - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, true) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres", "ffdx", "ipfs", "erc721", "bad_unknown_plugin"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} +func TestBlockchainPlugin(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + bifactory.InitConfig(blockchainConfig) + config.Set("plugins.blockchain", []fftypes.JSONObject{{}}) + blockchainConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + blockchainConfig.AddKnownKey(coreconfig.PluginConfigType, "ethereum") + plugins, err := nm.getBlockchainPlugins(context.Background()) + assert.Equal(t, 1, len(plugins)) + assert.NoError(t, err) +} - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10390.*unknown", err) +func TestBlockchainPluginNoType(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + bifactory.InitConfig(blockchainConfig) + config.Set("plugins.blockchain", []fftypes.JSONObject{{}}) + blockchainConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + _, err := nm.getBlockchainPlugins(context.Background()) + assert.Error(t, err) } -func TestInitNamespacesMultipartyMultipleBlockchains(t *testing.T) { +func TestBlockchainPluginBadType(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) + nm.blockchains = nil + bifactory.InitConfig(blockchainConfig) + config.Set("plugins.blockchain", []fftypes.JSONObject{{}}) + blockchainConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + blockchainConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong//") + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.Error(t, err) +} - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, true) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres", "ffdx", "ipfs", "erc721", "fabric"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} +func TestDeprecatedSharedStoragePlugin(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + ssfactory.InitConfigDeprecated(deprecatedSharedStorageConfig) + deprecatedSharedStorageConfig.Set(coreconfig.PluginConfigType, "ipfs") + plugins, err := nm.getSharedStoragePlugins(context.Background()) + assert.Equal(t, 1, len(plugins)) + assert.NoError(t, err) +} - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10394", err) +func TestDeprecatedSharedStoragePluginBadType(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + ssfactory.InitConfigDeprecated(deprecatedSharedStorageConfig) + deprecatedSharedStorageConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong") + _, err := nm.getSharedStoragePlugins(context.Background()) + assert.Regexp(t, "FF10134.*wrong", err) } -func TestInitNamespacesMultipartyMultipleDX(t *testing.T) { +func TestSharedStoragePlugin(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) + ssfactory.InitConfig(sharedstorageConfig) + config.Set("plugins.sharedstorage", []fftypes.JSONObject{{}}) + sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigType, "ipfs") + plugins, err := nm.getSharedStoragePlugins(context.Background()) + assert.Equal(t, 1, len(plugins)) + assert.NoError(t, err) +} - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, true) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres", "ffdx", "ipfs", "erc721", "ffdx2"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} +func TestSharedStoragePluginNoType(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + ssfactory.InitConfig(sharedstorageConfig) + config.Set("plugins.sharedstorage", []fftypes.JSONObject{{}}) + sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + _, err := nm.getSharedStoragePlugins(context.Background()) + assert.Error(t, err) +} - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10394", err) +func TestSharedStoragePluginBadType(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + nm.sharedstorages = nil + ssfactory.InitConfig(sharedstorageConfig) + config.Set("plugins.sharedstorage", []fftypes.JSONObject{{}}) + sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong//") + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.Error(t, err) } -func TestInitNamespacesMultipartyMultipleSS(t *testing.T) { +func TestDeprecatedDataExchangePlugin(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) + dxfactory.InitConfigDeprecated(deprecatedDataexchangeConfig) + deprecatedDataexchangeConfig.Set(coreconfig.PluginConfigType, "ffdx") + plugins, err := nm.getDataExchangePlugins(context.Background()) + assert.Equal(t, 1, len(plugins)) + assert.NoError(t, err) +} - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, true) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres", "ffdx", "ipfs", "erc721", "ipfs2"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} +func TestDeprecatedDataExchangePluginBadType(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + dxfactory.InitConfigDeprecated(deprecatedDataexchangeConfig) + deprecatedDataexchangeConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong") + _, err := nm.getDataExchangePlugins(context.Background()) + assert.Regexp(t, "FF10213.*wrong", err) +} - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10394", err) +func TestDataExchangePlugin(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + dxfactory.InitConfig(dataexchangeConfig) + config.Set("plugins.dataexchange", []fftypes.JSONObject{{}}) + dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigType, "ffdx") + plugins, err := nm.getDataExchangePlugins(context.Background()) + assert.Equal(t, 1, len(plugins)) + assert.NoError(t, err) } -func TestInitNamespacesMultipartyMultipleDB(t *testing.T) { +func TestDataExchangePluginNoType(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) + dxfactory.InitConfig(dataexchangeConfig) + config.Set("plugins.dataexchange", []fftypes.JSONObject{{}}) + dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + _, err := nm.getDataExchangePlugins(context.Background()) + assert.Error(t, err) +} - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, true) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres", "ffdx", "ipfs", "erc721", "sqlite3"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} +func TestDataExchangePluginBadType(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + nm.dataexchanges = nil + dxfactory.InitConfig(dataexchangeConfig) + config.Set("plugins.dataexchange", []fftypes.JSONObject{{}}) + dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") + dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong//") + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.Error(t, err) +} - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10394", err) +func TestDeprecatedTokensPlugin(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + tifactory.InitConfigDeprecated(deprecatedTokensConfig) + config.Set("tokens", []fftypes.JSONObject{{}}) + deprecatedTokensConfig.AddKnownKey(coreconfig.PluginConfigName, "test") + deprecatedTokensConfig.AddKnownKey(tokens.TokensConfigPlugin, "fftokens") + plugins, err := nm.getTokensPlugins(context.Background()) + assert.Equal(t, 1, len(plugins)) + assert.NoError(t, err) } -func TestInitNamespacesDeprecatedConfigMultipleBlockchains(t *testing.T) { +func TestDeprecatedTokensPluginNoName(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) + tifactory.InitConfigDeprecated(deprecatedTokensConfig) + config.Set("tokens", []fftypes.JSONObject{{}}) + deprecatedTokensConfig.AddKnownKey(tokens.TokensConfigPlugin, "fftokens") + _, err := nm.getTokensPlugins(context.Background()) + assert.Regexp(t, "FF10273", err) +} - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, true) - utTestConfig.AddKnownKey(coreconfig.NamespaceDescription) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} +func TestDeprecatedTokensPluginBadName(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + tifactory.InitConfigDeprecated(deprecatedTokensConfig) + config.Set("tokens", []fftypes.JSONObject{{}}) + deprecatedTokensConfig.AddKnownKey(coreconfig.PluginConfigName, "BAD!") + deprecatedTokensConfig.AddKnownKey(tokens.TokensConfigPlugin, "fftokens") + _, err := nm.getTokensPlugins(context.Background()) + assert.Regexp(t, "FF00140", err) +} - // nm.mdi.On("GetNamespace", mock.Anything, mock.Anything).Return(nil, nil) - // nm.mdi.On("UpsertNamespace", mock.Anything, mock.Anything, true).Return(nil) +func TestDeprecatedTokensPluginBadType(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + tifactory.InitConfigDeprecated(deprecatedTokensConfig) + config.Set("tokens", []fftypes.JSONObject{{}}) + deprecatedTokensConfig.AddKnownKey(coreconfig.PluginConfigName, "test") + deprecatedTokensConfig.AddKnownKey(tokens.TokensConfigPlugin, "wrong") + _, err := nm.getTokensPlugins(context.Background()) + assert.Regexp(t, "FF10272.*wrong", err) +} - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10394", err) +func TestTokensPlugin(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + tifactory.InitConfig(tokensConfig) + config.Set("plugins.tokens", []fftypes.JSONObject{{}}) + tokensConfig.AddKnownKey(coreconfig.PluginConfigName, "erc20_erc721") + tokensConfig.AddKnownKey(coreconfig.PluginConfigType, "fftokens") + plugins, err := nm.getTokensPlugins(context.Background()) + assert.Equal(t, 1, len(plugins)) + assert.NoError(t, err) } -func TestInitNamespacesGatewayMultipleDB(t *testing.T) { +func TestTokensPluginNoType(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) + tifactory.InitConfig(tokensConfig) + config.Set("plugins.tokens", []fftypes.JSONObject{{}}) + tokensConfig.AddKnownKey(coreconfig.PluginConfigName, "erc20_erc721") + _, err := nm.getTokensPlugins(context.Background()) + assert.Error(t, err) +} - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, false) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres", "sqlite3"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} +func TestTokensPluginBadType(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + nm.tokens = nil + tifactory.InitConfig(tokensConfig) + config.Set("plugins.tokens", []fftypes.JSONObject{{}}) + tokensConfig.AddKnownKey(coreconfig.PluginConfigName, "erc20_erc721") + tokensConfig.AddKnownKey(coreconfig.PluginConfigType, "wrong") + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.Error(t, err) +} - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10394", err) +func TestTokensPluginDuplicate(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + nm.pluginNames["erc20_erc721"] = true + tifactory.InitConfig(tokensConfig) + config.Set("plugins.tokens", []fftypes.JSONObject{{}}) + tokensConfig.AddKnownKey(coreconfig.PluginConfigName, "erc20_erc721") + tokensConfig.AddKnownKey(coreconfig.PluginConfigType, "fftokens") + _, err := nm.getTokensPlugins(context.Background()) + assert.Regexp(t, "FF10395", err) } -func TestInitNamespacesGatewayMultipleBlockchains(t *testing.T) { +func TestInitNamespacesBadName(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, false) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres", "fabric"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: "!Badness" + predefined: + - name: "!Badness" + `)) + assert.NoError(t, err) - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10394", err) + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF00140", err) } -func TestInitNamespacesMultipartyMissingPlugins(t *testing.T) { +func TestInitNamespacesReservedName(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, true) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ff_system + `)) + assert.NoError(t, err) - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10391", err) + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10388", err) } -func TestInitNamespacesGatewayWithDX(t *testing.T) { +func TestInitNamespacesDuplicate(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, false) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "ffdx"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [postgres] + - name: ns1 + plugins: [postgres] + `)) + assert.NoError(t, err) - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10393", err) + err = nm.loadNamespaces(context.Background()) + assert.NoError(t, err) + assert.Len(t, nm.namespaces, 1) } -func TestInitNamespacesGatewayWithSharedStorage(t *testing.T) { +func TestInitNamespacesNoDefault(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, false) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "ipfs"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns2 + plugins: [postgres] + `)) + assert.NoError(t, err) - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10393", err) + ctx, cancelCtx := context.WithCancel(context.Background()) + err = nm.Init(ctx, cancelCtx) + assert.Regexp(t, "FF10166", err) } -func TestInitNamespacesGatewayUnknownPlugin(t *testing.T) { +func TestInitNamespacesUseDefaults(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, false) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "bad_unknown_plugin"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + org: + name: org1 + `)) + assert.NoError(t, err) - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10390.*unknown", err) + err = nm.loadNamespaces(context.Background()) + assert.NoError(t, err) + assert.Len(t, nm.namespaces, 1) } -func TestInitNamespacesGatewayNoDB(t *testing.T) { +func TestInitNamespacesGatewayNoDatabase(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, false) - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [] + `)) + assert.NoError(t, err) - err := nm.initNamespaces(context.Background(), nm.mdi) + err = nm.loadNamespaces(context.Background()) assert.Regexp(t, "FF10392", err) } -func TestInitNamespacesUpsertNotNeeded(t *testing.T) { +func TestInitNamespacesMultipartyUnknownPlugin(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [bad] + multiparty: + enabled: true + `)) + assert.NoError(t, err) + + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10390.*unknown", err) +} + +func TestInitNamespacesMultipartyMultipleBlockchains(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [ethereum, ethereum] + multiparty: + enabled: true + `)) + assert.NoError(t, err) + + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10394.*blockchain", err) +} + +func TestInitNamespacesMultipartyMultipleDX(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - utTestConfig := config.RootSection("default") - utTestConfig.AddKnownKey(coreconfig.NamespaceName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceRemoteName, "default") - utTestConfig.AddKnownKey(coreconfig.NamespaceMultipartyEnabled, true) - utTestConfig.AddKnownKey(coreconfig.NamespaceDescription, "test description") - utTestConfig.AddKnownKey(coreconfig.NamespacePlugins, []string{"ethereum", "postgres", "ffdx", "ipfs", "erc721"}) - nm.nsConfig = map[string]config.Section{"default": utTestConfig} + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [ffdx, ffdx] + multiparty: + enabled: true + `)) + assert.NoError(t, err) + + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10394.*dataexchange", err) +} - nm.mdi.On("GetNamespace", mock.Anything, mock.Anything).Return(&core.Namespace{ - Type: core.NamespaceTypeBroadcast, // any broadcasted NS will not be updated - }, nil) - err := nm.initNamespaces(context.Background(), nm.mdi) +func TestInitNamespacesMultipartyMultipleSS(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [ipfs, ipfs] + multiparty: + enabled: true + `)) assert.NoError(t, err) + + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10394.*sharedstorage", err) } -func TestInitNamespacesDefaultMissing(t *testing.T) { - coreconfig.Reset() - config.Set(coreconfig.NamespacesPredefined, fftypes.JSONObjectArray{}) +func TestInitNamespacesMultipartyMultipleDB(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [postgres, postgres] + multiparty: + enabled: true + `)) + assert.NoError(t, err) + + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10394.*database", err) +} - nm := newTestNamespaceManager(false) +func TestInitNamespacesGatewayMultipleDB(t *testing.T) { + nm := newTestNamespaceManager(true) defer nm.cleanup(t) - err := nm.initNamespaces(context.Background(), nm.mdi) - assert.Regexp(t, "FF10166", err) + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [postgres, postgres] + `)) + assert.NoError(t, err) + + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10394.*database", err) } -func TestInitNamespacesDupName(t *testing.T) { - coreconfig.Reset() - InitConfig(false) +func TestInitNamespacesGatewayMultipleBlockchains(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) viper.SetConfigType("yaml") err := viper.ReadConfig(strings.NewReader(` @@ -396,81 +723,185 @@ func TestInitNamespacesDupName(t *testing.T) { default: ns1 predefined: - name: ns1 - remoteName: ns1 - plugins: [sqlite3, ethereum, erc721] - - name: ns2 - remoteName: ns2 - plugins: - - sqlite3 - - ethereum - - erc721 - - name: ns2 - remoteName: ns2 - plugins: - - sqlite3 - - ethereum - - erc721 + plugins: [ethereum, ethereum] `)) assert.NoError(t, err) - nm := newTestNamespaceManager(false) + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10394.*blockchain", err) +} + +func TestInitNamespacesMultipartyMissingPlugins(t *testing.T) { + nm := newTestNamespaceManager(true) defer nm.cleanup(t) - nsList, err := nm.getPredefinedNamespaces(context.Background()) + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [postgres] + multiparty: + enabled: true + `)) assert.NoError(t, err) - assert.Len(t, nsList, 3) - names := make([]string, len(nsList)) - for i, ns := range nsList { - names[i] = ns.Name - } - assert.Contains(t, names, core.LegacySystemNamespace) - assert.Contains(t, names, "ns1") - assert.Contains(t, names, "ns2") + + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10391", err) +} + +func TestInitNamespacesGatewayWithDX(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [ffdx] + `)) + assert.NoError(t, err) + + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10393", err) } -func TestGetConfig(t *testing.T) { - coreconfig.Reset() - namespaceConfig.AddKnownKey("predefined.0."+coreconfig.NamespaceName, "ns1") - namespaceConfig.AddKnownKey("predefined.0."+coreconfig.NamespaceMultipartyOrgKey, "0x12345") +func TestInitNamespacesGatewayWithSharedStorage(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [ipfs] + `)) + assert.NoError(t, err) + + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10393", err) +} + +func TestInitNamespacesGatewayUnknownPlugin(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [bad] + `)) + assert.NoError(t, err) + + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10390.*unknown", err) +} - nm := newTestNamespaceManager(false) +func TestInitNamespacesGatewayTokens(t *testing.T) { + nm := newTestNamespaceManager(true) defer nm.cleanup(t) - key := nm.GetMultipartyConfig("ns1", coreconfig.OrgKey) - assert.Equal(t, "0x12345", key) + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + default: ns1 + predefined: + - name: ns1 + plugins: [postgres, erc721] + `)) + assert.NoError(t, err) + + err = nm.loadNamespaces(context.Background()) + assert.NoError(t, err) } -func TestGetConfigFallback(t *testing.T) { - coreconfig.Reset() - namespaceConfig.AddKnownKey("predefined.0."+coreconfig.NamespaceName, "ns1") - config.Set(coreconfig.OrgKey, "0x123") +func TestStart(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + mo := &orchestratormocks.Orchestrator{} + nm.namespaces = map[string]*namespace{ + "ns": {orchestrator: mo}, + } + nm.metricsEnabled = true + + mo.On("Start").Return(nil) - nm := newTestNamespaceManager(false) + err := nm.Start() + assert.NoError(t, err) + + mo.AssertExpectations(t) +} + +func TestStartFail(t *testing.T) { + nm := newTestNamespaceManager(true) defer nm.cleanup(t) - key := nm.GetMultipartyConfig("ns1", coreconfig.OrgKey) - assert.Equal(t, "0x123", key) + mo := &orchestratormocks.Orchestrator{} + nm.namespaces = map[string]*namespace{ + "ns": {orchestrator: mo}, + } + + mo.On("Start").Return(fmt.Errorf("pop")) + + err := nm.Start() + assert.EqualError(t, err, "pop") + + mo.AssertExpectations(t) } -func TestGetDefaultKey(t *testing.T) { - coreconfig.Reset() - namespaceConfig.AddKnownKey("predefined.0."+coreconfig.NamespaceName, "ns1") - namespaceConfig.AddKnownKey("predefined.0."+coreconfig.NamespaceDefaultKey, "0x12345") +func TestWaitStop(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + mo := &orchestratormocks.Orchestrator{} + nm.namespaces = map[string]*namespace{ + "ns": {orchestrator: mo}, + } + mae := nm.adminEvents.(*admineventsmocks.Manager) + + mo.On("WaitStop").Return() + mae.On("WaitStop").Return() + + nm.WaitStop() + + mo.AssertExpectations(t) + mae.AssertExpectations(t) +} - nm := newTestNamespaceManager(false) +func TestLoadMetrics(t *testing.T) { + nm := newTestNamespaceManager(true) defer nm.cleanup(t) - key := nm.GetDefaultKey("ns1") - assert.Equal(t, "0x12345", key) + nm.metrics = nil + + err := nm.loadPlugins(context.Background()) + assert.NoError(t, err) } -func TestGetDefaultKeyNotFound(t *testing.T) { - coreconfig.Reset() +func TestLoadAdminEvents(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + nm.adminEvents = nil - nm := newTestNamespaceManager(false) + err := nm.loadPlugins(context.Background()) + assert.NoError(t, err) + assert.NotNil(t, nm.AdminEvents()) +} + +func TestGetNamespaces(t *testing.T) { + nm := newTestNamespaceManager(true) defer nm.cleanup(t) - key := nm.GetDefaultKey("ns1") - assert.Equal(t, "", key) + fb := database.NamespaceQueryFactory.NewFilter(context.Background()) + nm.GetNamespaces(context.Background(), fb.And()) } -*/ From ccc87cb019be67e0ba9c700331d81d4cfccec7f9 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Mon, 6 Jun 2022 16:22:26 -0400 Subject: [PATCH 14/33] Implement GetNamespaces on namespace manager Returns very basic information about all available namespaces. Note that there is no "GetNamespaces" query on orchestrator or the database layer now, as these details may be spread across multiple databases. Signed-off-by: Andrew Richardson --- docs/swagger/swagger.yaml | 69 ------------------- internal/apiserver/route_get_namespaces.go | 5 +- .../apiserver/route_get_namespaces_test.go | 8 ++- internal/apiserver/routes.go | 2 + internal/apiserver/server.go | 1 + internal/database/sqlcommon/namespace_sql.go | 30 -------- .../database/sqlcommon/namespace_sql_test.go | 42 +---------- internal/events/event_manager.go | 4 +- internal/events/event_manager_test.go | 6 +- internal/events/network_action.go | 14 ++-- internal/events/network_action_test.go | 8 +-- internal/namespace/manager.go | 63 +++++++++-------- internal/namespace/manager_test.go | 10 ++- internal/orchestrator/data_query.go | 4 -- internal/orchestrator/data_query_test.go | 9 --- internal/orchestrator/orchestrator.go | 3 +- mocks/databasemocks/plugin.go | 32 --------- mocks/eventmocks/event_manager.go | 16 ----- mocks/metricsmocks/manager.go | 14 ---- mocks/namespacemocks/manager.go | 31 +++------ mocks/orchestratormocks/orchestrator.go | 32 --------- pkg/database/plugin.go | 14 ---- 22 files changed, 81 insertions(+), 336 deletions(-) diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 08fa3a3bd8..a80895922f 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -8302,75 +8302,6 @@ paths: schema: default: 2m0s type: string - - description: 'Data filter field. Prefixes supported: > >= < <= @ ^ ! !@ !^' - in: query - name: confirmed - 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: description - 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: 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: 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: diff --git a/internal/apiserver/route_get_namespaces.go b/internal/apiserver/route_get_namespaces.go index 1ae144e52f..5d76670265 100644 --- a/internal/apiserver/route_get_namespaces.go +++ b/internal/apiserver/route_get_namespaces.go @@ -22,7 +22,6 @@ import ( "github.com/hyperledger/firefly-common/pkg/ffapi" "github.com/hyperledger/firefly/internal/coremsgs" "github.com/hyperledger/firefly/pkg/core" - "github.com/hyperledger/firefly/pkg/database" ) var getNamespaces = &ffapi.Route{ @@ -36,9 +35,9 @@ var getNamespaces = &ffapi.Route{ JSONOutputValue: func() interface{} { return []*core.Namespace{} }, JSONOutputCodes: []int{http.StatusOK}, Extensions: &coreExtensions{ - FilterFactory: database.NamespaceQueryFactory, + FilterFactory: nil, CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { - return filterResult(cr.or.GetNamespaces(cr.ctx, cr.filter)) + return cr.mgr.GetNamespaces(cr.ctx) }, }, } diff --git a/internal/apiserver/route_get_namespaces_test.go b/internal/apiserver/route_get_namespaces_test.go index 896d41cc12..8e2bf0be35 100644 --- a/internal/apiserver/route_get_namespaces_test.go +++ b/internal/apiserver/route_get_namespaces_test.go @@ -17,6 +17,7 @@ package apiserver import ( + "context" "net/http/httptest" "testing" @@ -26,13 +27,14 @@ import ( ) func TestGetNamespaces(t *testing.T) { - o, r := newTestAPIServer() + mgr, _, as := newTestServer() + r := as.createMuxRouter(context.Background(), mgr) req := httptest.NewRequest("GET", "/api/v1/namespaces", nil) req.Header.Set("Content-Type", "application/json; charset=utf-8") res := httptest.NewRecorder() - o.On("GetNamespaces", mock.Anything, mock.Anything). - Return([]*core.Namespace{}, nil, nil) + mgr.On("GetNamespaces", mock.Anything). + Return([]*core.Namespace{}, nil) r.ServeHTTP(res, req) assert.Equal(t, 200, res.Result().StatusCode) diff --git a/internal/apiserver/routes.go b/internal/apiserver/routes.go index 856764e8ff..19e1738b73 100644 --- a/internal/apiserver/routes.go +++ b/internal/apiserver/routes.go @@ -23,11 +23,13 @@ import ( "github.com/hyperledger/firefly-common/pkg/ffapi" "github.com/hyperledger/firefly/internal/coreconfig" "github.com/hyperledger/firefly/internal/coremsgs" + "github.com/hyperledger/firefly/internal/namespace" "github.com/hyperledger/firefly/internal/orchestrator" "github.com/hyperledger/firefly/pkg/database" ) type coreRequest struct { + mgr namespace.Manager or orchestrator.Orchestrator ctx context.Context filter database.AndFilter diff --git a/internal/apiserver/server.go b/internal/apiserver/server.go index 8877da72a8..5d045b0056 100644 --- a/internal/apiserver/server.go +++ b/internal/apiserver/server.go @@ -233,6 +233,7 @@ func (as *apiServer) routeHandler(hf *ffapi.HandlerFactory, mgr namespace.Manage vars := mux.Vars(r.Req) or := mgr.Orchestrator(extractNamespace(vars)) cr := &coreRequest{ + mgr: mgr, or: or, ctx: r.Req.Context(), filter: filter, diff --git a/internal/database/sqlcommon/namespace_sql.go b/internal/database/sqlcommon/namespace_sql.go index 7a3c2623ec..79526917f1 100644 --- a/internal/database/sqlcommon/namespace_sql.go +++ b/internal/database/sqlcommon/namespace_sql.go @@ -39,10 +39,6 @@ var ( "created", "firefly_contracts", } - namespaceFilterFieldMap = map[string]string{ - "message": "message_id", - "type": "ntype", - } ) const namespacesTable = "namespaces" @@ -176,32 +172,6 @@ func (s *SQLCommon) GetNamespaceByID(ctx context.Context, id *fftypes.UUID) (ns return s.getNamespaceEq(ctx, sq.Eq{"id": id}, id.String()) } -func (s *SQLCommon) GetNamespaces(ctx context.Context, filter database.Filter) (message []*core.Namespace, fr *database.FilterResult, err error) { - - query, fop, fi, err := s.filterSelect(ctx, "", sq.Select(namespaceColumns...).From(namespacesTable), filter, namespaceFilterFieldMap, []interface{}{"sequence"}) - if err != nil { - return nil, nil, err - } - - rows, tx, err := s.query(ctx, namespacesTable, query) - if err != nil { - return nil, nil, err - } - defer rows.Close() - - namespace := []*core.Namespace{} - for rows.Next() { - d, err := s.namespaceResult(ctx, rows) - if err != nil { - return nil, nil, err - } - namespace = append(namespace, d) - } - - return namespace, s.queryRes(ctx, namespacesTable, tx, fop, fi), err - -} - func (s *SQLCommon) DeleteNamespace(ctx context.Context, id *fftypes.UUID) (err error) { ctx, tx, autoCommit, err := s.beginOrUseTx(ctx) diff --git a/internal/database/sqlcommon/namespace_sql_test.go b/internal/database/sqlcommon/namespace_sql_test.go index b930de9a09..f65176ee9b 100644 --- a/internal/database/sqlcommon/namespace_sql_test.go +++ b/internal/database/sqlcommon/namespace_sql_test.go @@ -93,26 +93,13 @@ func TestNamespacesE2EWithDB(t *testing.T) { namespaceReadJson, _ = json.Marshal(&namespaceRead) assert.Equal(t, string(namespaceJson), string(namespaceReadJson)) - // Query back the namespace - fb := database.NamespaceQueryFactory.NewFilter(ctx) - filter := fb.And( - fb.Eq("type", string(namespaceUpdated.Type)), - fb.Eq("name", namespaceUpdated.Name), - ) - namespaceRes, res, err := s.GetNamespaces(ctx, filter.Count(true)) - assert.NoError(t, err) - assert.Equal(t, 1, len(namespaceRes)) - assert.Equal(t, int64(1), *res.TotalCount) - namespaceReadJson, _ = json.Marshal(namespaceRes[0]) - assert.Equal(t, string(namespaceJson), string(namespaceReadJson)) - // Delete s.callbacks.On("UUIDCollectionEvent", database.CollectionNamespaces, core.ChangeEventTypeDeleted, namespace.ID, mock.Anything).Return() err = s.DeleteNamespace(ctx, namespaceUpdated.ID) assert.NoError(t, err) - namespaces, _, err := s.GetNamespaces(ctx, filter) + namespaceRead, err = s.GetNamespace(ctx, namespace.Name) assert.NoError(t, err) - assert.Equal(t, 0, len(namespaces)) + assert.Nil(t, namespaceRead) s.callbacks.AssertExpectations(t) } @@ -194,22 +181,6 @@ func TestGetNamespaceByNameScanFail(t *testing.T) { assert.NoError(t, mock.ExpectationsWereMet()) } -func TestGetNamespaceQueryFail(t *testing.T) { - s, mock := newMockProvider().init() - mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop")) - f := database.NamespaceQueryFactory.NewFilter(context.Background()).Eq("type", "") - _, _, err := s.GetNamespaces(context.Background(), f) - assert.Regexp(t, "FF10115", err) - assert.NoError(t, mock.ExpectationsWereMet()) -} - -func TestGetNamespaceBuildQueryFail(t *testing.T) { - s, _ := newMockProvider().init() - f := database.NamespaceQueryFactory.NewFilter(context.Background()).Eq("type", map[bool]bool{true: false}) - _, _, err := s.GetNamespaces(context.Background(), f) - assert.Regexp(t, "FF00143.*type", err) -} - func TestGetNamespaceByIDQueryFail(t *testing.T) { s, mock := newMockProvider().init() mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop")) @@ -258,15 +229,6 @@ func TestGetNamespaceByIDSuccess(t *testing.T) { assert.NoError(t, mock.ExpectationsWereMet()) } -func TestGetNamespaceReadMessageFail(t *testing.T) { - s, mock := newMockProvider().init() - mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"ntype"}).AddRow("only one")) - f := database.NamespaceQueryFactory.NewFilter(context.Background()).Eq("type", "") - _, _, err := s.GetNamespaces(context.Background(), f) - assert.Regexp(t, "FF10121", err) - assert.NoError(t, mock.ExpectationsWereMet()) -} - func TestNamespaceDeleteBeginFail(t *testing.T) { s, mock := newMockProvider().init() mock.ExpectBegin().WillReturnError(fmt.Errorf("pop")) diff --git a/internal/events/event_manager.go b/internal/events/event_manager.go index 4e0107dc2b..293d32c553 100644 --- a/internal/events/event_manager.go +++ b/internal/events/event_manager.go @@ -87,6 +87,7 @@ type EventManager interface { type eventManager struct { ctx context.Context + namespace string ni sysmessaging.LocalNodeInfo sharedstorage sharedstorage.Plugin database database.Plugin @@ -111,7 +112,7 @@ type eventManager struct { chainListenerCacheTTL time.Duration } -func NewEventManager(ctx context.Context, ni sysmessaging.LocalNodeInfo, si sharedstorage.Plugin, di database.Plugin, bi blockchain.Plugin, im identity.Manager, dh definitions.DefinitionHandler, dm data.Manager, bm broadcast.Manager, pm privatemessaging.Manager, am assets.Manager, sd shareddownload.Manager, mm metrics.Manager, txHelper txcommon.Helper) (EventManager, error) { +func NewEventManager(ctx context.Context, ns string, ni sysmessaging.LocalNodeInfo, si sharedstorage.Plugin, di database.Plugin, bi blockchain.Plugin, im identity.Manager, dh definitions.DefinitionHandler, dm data.Manager, bm broadcast.Manager, pm privatemessaging.Manager, am assets.Manager, sd shareddownload.Manager, mm metrics.Manager, txHelper txcommon.Helper) (EventManager, error) { if ni == nil || si == nil || di == nil || bi == nil || im == nil || dh == nil || dm == nil || bm == nil || pm == nil || am == nil { return nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError, "EventManager") } @@ -119,6 +120,7 @@ func NewEventManager(ctx context.Context, ni sysmessaging.LocalNodeInfo, si shar newEventNotifier := newEventNotifier(ctx, "events") em := &eventManager{ ctx: log.WithLogField(ctx, "role", "event-manager"), + namespace: ns, ni: ni, sharedstorage: si, database: di, diff --git a/internal/events/event_manager_test.go b/internal/events/event_manager_test.go index 6ce2ee73df..96f5db2a0d 100644 --- a/internal/events/event_manager_test.go +++ b/internal/events/event_manager_test.go @@ -89,7 +89,7 @@ func newTestEventManagerCommon(t *testing.T, metrics, dbconcurrency bool) (*even met.On("Name").Return("ut").Maybe() mbi.On("VerifierType").Return(core.VerifierTypeEthAddress).Maybe() mdi.On("Capabilities").Return(&database.Capabilities{Concurrency: dbconcurrency}).Maybe() - emi, err := NewEventManager(ctx, mni, mpi, mdi, mbi, mim, msh, mdm, mbm, mpm, mam, mdd, mmi, txHelper) + emi, err := NewEventManager(ctx, "ns1", mni, mpi, mdi, mbi, mim, msh, mdm, mbm, mpm, mam, mdd, mmi, txHelper) em := emi.(*eventManager) em.txHelper = &txcommonmocks.Helper{} mockRunAsGroupPassthrough(mdi) @@ -124,7 +124,7 @@ func TestStartStop(t *testing.T) { } func TestStartStopBadDependencies(t *testing.T) { - _, err := NewEventManager(context.Background(), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + _, err := NewEventManager(context.Background(), "", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) assert.Regexp(t, "FF10128", err) } @@ -147,7 +147,7 @@ func TestStartStopBadTransports(t *testing.T) { txHelper := txcommon.NewTransactionHelper(mdi, mdm) mdi.On("Capabilities").Return(&database.Capabilities{Concurrency: false}).Maybe() mbi.On("VerifierType").Return(core.VerifierTypeEthAddress) - _, err := NewEventManager(context.Background(), mni, mpi, mdi, mbi, mim, msh, mdm, mbm, mpm, mam, msd, mm, txHelper) + _, err := NewEventManager(context.Background(), "ns1", mni, mpi, mdi, mbi, mim, msh, mdm, mbm, mpm, mam, msd, mm, txHelper) assert.Regexp(t, "FF10172", err) } diff --git a/internal/events/network_action.go b/internal/events/network_action.go index 60f7a70f42..537e94a645 100644 --- a/internal/events/network_action.go +++ b/internal/events/network_action.go @@ -22,26 +22,22 @@ import ( "github.com/hyperledger/firefly-common/pkg/log" "github.com/hyperledger/firefly/pkg/blockchain" "github.com/hyperledger/firefly/pkg/core" - "github.com/hyperledger/firefly/pkg/database" ) func (em *eventManager) actionTerminate(bi blockchain.Plugin, event *blockchain.Event) error { - f := database.NamespaceQueryFactory.NewFilter(em.ctx) - namespaces, _, err := em.database.GetNamespaces(em.ctx, f.And()) + namespace, err := em.database.GetNamespace(em.ctx, em.namespace) if err != nil { return err } - contracts := &namespaces[0].Contracts + contracts := &namespace.Contracts if err := bi.TerminateContract(em.ctx, contracts, event); err != nil { return err } // Currently, a termination event is implied to apply to ALL namespaces return em.database.RunAsGroup(em.ctx, func(ctx context.Context) error { - for _, ns := range namespaces { - ns.Contracts = *contracts - if err := em.database.UpsertNamespace(em.ctx, ns, true); err != nil { - return err - } + namespace.Contracts = *contracts + if err := em.database.UpsertNamespace(em.ctx, namespace, true); err != nil { + return err } return nil }) diff --git a/internal/events/network_action_test.go b/internal/events/network_action_test.go index 28d86cbae7..5fdadea3d6 100644 --- a/internal/events/network_action_test.go +++ b/internal/events/network_action_test.go @@ -52,7 +52,7 @@ func TestNetworkAction(t *testing.T) { return be.ProtocolID == "0001" })).Return(nil) mdi.On("InsertEvent", em.ctx, mock.Anything).Return(nil) - mdi.On("GetNamespaces", em.ctx, mock.Anything).Return([]*core.Namespace{{}}, nil, nil) + mdi.On("GetNamespace", em.ctx, "ns1").Return(&core.Namespace{}, nil) mdi.On("UpsertNamespace", em.ctx, mock.AnythingOfType("*core.Namespace"), true).Return(nil) mbi.On("TerminateContract", em.ctx, mock.AnythingOfType("*core.FireFlyContracts"), mock.AnythingOfType("*blockchain.Event")).Return(nil) @@ -140,7 +140,7 @@ func TestActionTerminateQueryFail(t *testing.T) { mbi := &blockchainmocks.Plugin{} mdi := em.database.(*databasemocks.Plugin) - mdi.On("GetNamespaces", em.ctx, mock.Anything).Return(nil, nil, fmt.Errorf("pop")) + mdi.On("GetNamespace", em.ctx, "ns1").Return(nil, fmt.Errorf("pop")) err := em.actionTerminate(mbi, &blockchain.Event{}) assert.EqualError(t, err, "pop") @@ -156,7 +156,7 @@ func TestActionTerminateFail(t *testing.T) { mbi := &blockchainmocks.Plugin{} mdi := em.database.(*databasemocks.Plugin) - mdi.On("GetNamespaces", em.ctx, mock.Anything).Return([]*core.Namespace{{}}, nil, nil) + mdi.On("GetNamespace", em.ctx, "ns1").Return(&core.Namespace{}, nil) mbi.On("TerminateContract", em.ctx, mock.AnythingOfType("*core.FireFlyContracts"), mock.AnythingOfType("*blockchain.Event")).Return(fmt.Errorf("pop")) err := em.actionTerminate(mbi, &blockchain.Event{}) @@ -173,7 +173,7 @@ func TestActionTerminateUpsertFail(t *testing.T) { mbi := &blockchainmocks.Plugin{} mdi := em.database.(*databasemocks.Plugin) - mdi.On("GetNamespaces", em.ctx, mock.Anything).Return([]*core.Namespace{{}}, nil, nil) + mdi.On("GetNamespace", em.ctx, "ns1").Return(&core.Namespace{}, nil) mdi.On("UpsertNamespace", em.ctx, mock.AnythingOfType("*core.Namespace"), true).Return(fmt.Errorf("pop")) mbi.On("TerminateContract", em.ctx, mock.AnythingOfType("*core.FireFlyContracts"), mock.AnythingOfType("*blockchain.Event")).Return(nil) diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index 36a699a349..94ab1b8962 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -35,7 +35,6 @@ import ( "github.com/hyperledger/firefly/internal/sharedstorage/ssfactory" "github.com/hyperledger/firefly/internal/tokens/tifactory" "github.com/hyperledger/firefly/pkg/core" - "github.com/hyperledger/firefly/pkg/database" "github.com/hyperledger/firefly/pkg/tokens" ) @@ -62,10 +61,11 @@ type Manager interface { Orchestrator(ns string) orchestrator.Orchestrator AdminEvents() adminevents.Manager - GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) + GetNamespaces(ctx context.Context) ([]*core.Namespace, error) } type namespace struct { + description string orchestrator orchestrator.Orchestrator config orchestrator.Config } @@ -495,8 +495,8 @@ func (nm *namespaceManager) loadNamespaces(ctx context.Context) (err error) { i := 0 foundDefault := false - for name, nsObject := range namespaces { - if err := nm.loadNamespace(ctx, name, i, nsObject); err != nil { + for name, nsConfig := range namespaces { + if err := nm.loadNamespace(ctx, name, i, nsConfig); err != nil { return err } i++ @@ -508,7 +508,7 @@ func (nm *namespaceManager) loadNamespaces(ctx context.Context) (err error) { return err } -func (nm *namespaceManager) loadNamespace(ctx context.Context, name string, index int, conf config.Section) error { +func (nm *namespaceManager) loadNamespace(ctx context.Context, name string, index int, conf config.Section) (err error) { if err := core.ValidateFFNameField(ctx, name, fmt.Sprintf("namespaces.predefined[%d].name", index)); err != nil { return err } @@ -576,26 +576,33 @@ func (nm *namespaceManager) loadNamespace(ctx context.Context, name string, inde OrgKey: orgKey, OrgDesc: orgDesc, } - return nm.validateMultiPartyConfig(ctx, name, config, plugins) + err = nm.validateMultiPartyConfig(ctx, name, &config, plugins) + } else { + err = nm.validateGatewayConfig(ctx, name, &config, plugins) } - return nm.validateGatewayConfig(ctx, name, config, plugins) + + if err == nil { + nm.namespaces[name] = &namespace{ + description: conf.GetString(coreconfig.NamespaceDescription), + config: config, + } + } + return err } -func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name string, config orchestrator.Config, plugins []string) error { +func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name string, config *orchestrator.Config, plugins []string) error { var dbPlugin bool var ssPlugin bool var dxPlugin bool var bcPlugin bool - ns := &namespace{config: config} - for _, pluginName := range plugins { if instance, ok := nm.blockchains[pluginName]; ok { if bcPlugin { return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") } bcPlugin = true - ns.config.Blockchain = instance + config.Blockchain = instance continue } if instance, ok := nm.dataexchanges[pluginName]; ok { @@ -603,7 +610,7 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "dataexchange") } dxPlugin = true - ns.config.Dataexchange = instance + config.Dataexchange = instance continue } if instance, ok := nm.sharedstorages[pluginName]; ok { @@ -611,7 +618,7 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "sharedstorage") } ssPlugin = true - ns.config.Sharedstorage = instance + config.Sharedstorage = instance continue } if instance, ok := nm.databases[pluginName]; ok { @@ -619,15 +626,15 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") } dbPlugin = true - ns.config.Database = instance + config.Database = instance continue } if instance, ok := nm.tokens[pluginName]; ok { - ns.config.Tokens[pluginName] = instance + config.Tokens[pluginName] = instance continue } if instance, ok := nm.identities[pluginName]; ok { - ns.config.Identity = instance + config.Identity = instance continue } @@ -637,24 +644,21 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s if !dbPlugin || !ssPlugin || !dxPlugin || !bcPlugin { return i18n.NewError(ctx, coremsgs.MsgNamespaceMultipartyConfiguration, name) } - nm.namespaces[name] = ns return nil } -func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name string, config orchestrator.Config, plugins []string) error { +func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name string, config *orchestrator.Config, plugins []string) error { var dbPlugin bool var bcPlugin bool - ns := &namespace{config: config} - for _, pluginName := range plugins { if instance, ok := nm.blockchains[pluginName]; ok { if bcPlugin { return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") } bcPlugin = true - ns.config.Blockchain = instance + config.Blockchain = instance continue } if _, ok := nm.dataexchanges[pluginName]; ok { @@ -668,11 +672,11 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name stri return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") } dbPlugin = true - ns.config.Database = instance + config.Database = instance continue } if instance, ok := nm.tokens[pluginName]; ok { - ns.config.Tokens[pluginName] = instance + config.Tokens[pluginName] = instance continue } @@ -682,7 +686,6 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name stri if !dbPlugin { return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayNoDB, name) } - nm.namespaces[name] = ns return nil } @@ -698,7 +701,13 @@ func (nm *namespaceManager) Orchestrator(ns string) orchestrator.Orchestrator { return nil } -func (nm *namespaceManager) GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) { - // TODO: implement - return nil, nil, nil +func (nm *namespaceManager) GetNamespaces(ctx context.Context) ([]*core.Namespace, error) { + results := make([]*core.Namespace, 0, len(nm.namespaces)) + for name, ns := range nm.namespaces { + results = append(results, &core.Namespace{ + Name: name, + Description: ns.description, + }) + } + return results, nil } diff --git a/internal/namespace/manager_test.go b/internal/namespace/manager_test.go index ffb62b23dc..75e3e217e6 100644 --- a/internal/namespace/manager_test.go +++ b/internal/namespace/manager_test.go @@ -41,7 +41,6 @@ import ( "github.com/hyperledger/firefly/mocks/orchestratormocks" "github.com/hyperledger/firefly/mocks/sharedstoragemocks" "github.com/hyperledger/firefly/mocks/tokenmocks" - "github.com/hyperledger/firefly/pkg/database" "github.com/hyperledger/firefly/pkg/tokens" "github.com/spf13/viper" "github.com/stretchr/testify/assert" @@ -902,6 +901,11 @@ func TestGetNamespaces(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - fb := database.NamespaceQueryFactory.NewFilter(context.Background()) - nm.GetNamespaces(context.Background(), fb.And()) + nm.namespaces = map[string]*namespace{ + "default": {}, + } + + results, err := nm.GetNamespaces(context.Background()) + assert.Nil(t, err) + assert.Len(t, results, 1) } diff --git a/internal/orchestrator/data_query.go b/internal/orchestrator/data_query.go index 2f678c3149..95ee0b317e 100644 --- a/internal/orchestrator/data_query.go +++ b/internal/orchestrator/data_query.go @@ -203,10 +203,6 @@ func (or *orchestrator) GetEventByID(ctx context.Context, ns, id string) (*core. return e, err } -func (or *orchestrator) GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) { - return or.database.GetNamespaces(ctx, filter) -} - func (or *orchestrator) scopeNS(ns string, filter database.AndFilter) database.AndFilter { return filter.Condition(filter.Builder().Eq("namespace", ns)) } diff --git a/internal/orchestrator/data_query_test.go b/internal/orchestrator/data_query_test.go index 7b69e9dfe4..1ce3687cba 100644 --- a/internal/orchestrator/data_query_test.go +++ b/internal/orchestrator/data_query_test.go @@ -62,15 +62,6 @@ func TestGetTransactionOperationBadID(t *testing.T) { assert.Regexp(t, "FF00138", err) } -func TestGetNamespaces(t *testing.T) { - or := newTestOrchestrator() - or.mdi.On("GetNamespaces", mock.Anything, mock.Anything).Return([]*core.Namespace{}, nil, nil) - fb := database.NamespaceQueryFactory.NewFilter(context.Background()) - f := fb.And(fb.Eq("name", "ns1")) - _, _, err := or.GetNamespaces(context.Background(), f) - assert.NoError(t, err) -} - func TestGetTransactions(t *testing.T) { or := newTestOrchestrator() u := fftypes.NewUUID() diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index f60ceb8cfc..227f4d948a 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -77,7 +77,6 @@ type Orchestrator interface { // Data Query GetNamespace(ctx context.Context, ns string) (*core.Namespace, error) - GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) GetTransactionByID(ctx context.Context, ns, id string) (*core.Transaction, error) GetTransactionOperations(ctx context.Context, ns, id string) ([]*core.Operation, *database.FilterResult, error) GetTransactionBlockchainEvents(ctx context.Context, ns, id string) ([]*core.BlockchainEvent, *database.FilterResult, error) @@ -477,7 +476,7 @@ func (or *orchestrator) initComponents(ctx context.Context) (err error) { } if or.events == nil { - or.events, err = events.NewEventManager(ctx, or, or.sharedstorage, or.database, or.blockchain, or.identity, or.definitions, or.data, or.broadcast, or.messaging, or.assets, or.sharedDownload, or.metrics, or.txHelper) + or.events, err = events.NewEventManager(ctx, or.namespace, or, or.sharedstorage, or.database, or.blockchain, or.identity, or.definitions, or.data, or.broadcast, or.messaging, or.assets, or.sharedDownload, or.metrics, or.txHelper) if err != nil { return err } diff --git a/mocks/databasemocks/plugin.go b/mocks/databasemocks/plugin.go index a08370f5cc..28f3df7793 100644 --- a/mocks/databasemocks/plugin.go +++ b/mocks/databasemocks/plugin.go @@ -1397,38 +1397,6 @@ func (_m *Plugin) GetNamespaceByID(ctx context.Context, id *fftypes.UUID) (*core return r0, r1 } -// GetNamespaces provides a mock function with given fields: ctx, filter -func (_m *Plugin) GetNamespaces(ctx context.Context, filter database.Filter) ([]*core.Namespace, *database.FilterResult, error) { - ret := _m.Called(ctx, filter) - - var r0 []*core.Namespace - if rf, ok := ret.Get(0).(func(context.Context, database.Filter) []*core.Namespace); ok { - r0 = rf(ctx, filter) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*core.Namespace) - } - } - - var r1 *database.FilterResult - if rf, ok := ret.Get(1).(func(context.Context, database.Filter) *database.FilterResult); ok { - r1 = rf(ctx, 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, database.Filter) error); ok { - r2 = rf(ctx, filter) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - // GetNextPinByContextAndIdentity provides a mock function with given fields: ctx, _a1, identity func (_m *Plugin) GetNextPinByContextAndIdentity(ctx context.Context, _a1 *fftypes.Bytes32, identity string) (*core.NextPin, error) { ret := _m.Called(ctx, _a1, identity) diff --git a/mocks/eventmocks/event_manager.go b/mocks/eventmocks/event_manager.go index 82c759cbcc..a9804dc847 100644 --- a/mocks/eventmocks/event_manager.go +++ b/mocks/eventmocks/event_manager.go @@ -148,22 +148,6 @@ func (_m *EventManager) GetPlugins() []*core.NodeStatusPlugin { return r0 } -// GetWebSocketStatus provides a mock function with given fields: -func (_m *EventManager) GetWebSocketStatus() *core.WebSocketStatus { - ret := _m.Called() - - var r0 *core.WebSocketStatus - if rf, ok := ret.Get(0).(func() *core.WebSocketStatus); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*core.WebSocketStatus) - } - } - - return r0 -} - // NewEvents provides a mock function with given fields: func (_m *EventManager) NewEvents() chan<- int64 { ret := _m.Called() diff --git a/mocks/metricsmocks/manager.go b/mocks/metricsmocks/manager.go index 3f781ff52c..06b48037f4 100644 --- a/mocks/metricsmocks/manager.go +++ b/mocks/metricsmocks/manager.go @@ -84,20 +84,6 @@ func (_m *Manager) MessageSubmitted(msg *core.Message) { _m.Called(msg) } -// Start provides a mock function with given fields: -func (_m *Manager) Start() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - // TransferConfirmed provides a mock function with given fields: transfer func (_m *Manager) TransferConfirmed(transfer *core.TokenTransfer) { _m.Called(transfer) diff --git a/mocks/namespacemocks/manager.go b/mocks/namespacemocks/manager.go index 392666706b..34996661e0 100644 --- a/mocks/namespacemocks/manager.go +++ b/mocks/namespacemocks/manager.go @@ -9,8 +9,6 @@ import ( core "github.com/hyperledger/firefly/pkg/core" - database "github.com/hyperledger/firefly/pkg/database" - mock "github.com/stretchr/testify/mock" orchestrator "github.com/hyperledger/firefly/internal/orchestrator" @@ -37,36 +35,27 @@ func (_m *Manager) AdminEvents() adminevents.Manager { return r0 } -// GetNamespaces provides a mock function with given fields: ctx, filter -func (_m *Manager) GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) { - ret := _m.Called(ctx, filter) +// GetNamespaces provides a mock function with given fields: ctx +func (_m *Manager) GetNamespaces(ctx context.Context) ([]*core.Namespace, error) { + ret := _m.Called(ctx) var r0 []*core.Namespace - if rf, ok := ret.Get(0).(func(context.Context, database.AndFilter) []*core.Namespace); ok { - r0 = rf(ctx, filter) + if rf, ok := ret.Get(0).(func(context.Context) []*core.Namespace); ok { + r0 = rf(ctx) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*core.Namespace) } } - var r1 *database.FilterResult - if rf, ok := ret.Get(1).(func(context.Context, database.AndFilter) *database.FilterResult); ok { - r1 = rf(ctx, 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, database.AndFilter) error); ok { - r2 = rf(ctx, filter) + var r1 error + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) } else { - r2 = ret.Error(2) + r1 = ret.Error(1) } - return r0, r1, r2 + return r0, r1 } // Init provides a mock function with given fields: ctx, cancelCtx diff --git a/mocks/orchestratormocks/orchestrator.go b/mocks/orchestratormocks/orchestrator.go index fc50d67e39..66df32e3b1 100644 --- a/mocks/orchestratormocks/orchestrator.go +++ b/mocks/orchestratormocks/orchestrator.go @@ -820,38 +820,6 @@ func (_m *Orchestrator) GetNamespace(ctx context.Context, ns string) (*core.Name return r0, r1 } -// GetNamespaces provides a mock function with given fields: ctx, filter -func (_m *Orchestrator) GetNamespaces(ctx context.Context, filter database.AndFilter) ([]*core.Namespace, *database.FilterResult, error) { - ret := _m.Called(ctx, filter) - - var r0 []*core.Namespace - if rf, ok := ret.Get(0).(func(context.Context, database.AndFilter) []*core.Namespace); ok { - r0 = rf(ctx, filter) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*core.Namespace) - } - } - - var r1 *database.FilterResult - if rf, ok := ret.Get(1).(func(context.Context, database.AndFilter) *database.FilterResult); ok { - r1 = rf(ctx, 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, database.AndFilter) error); ok { - r2 = rf(ctx, filter) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - // GetOperationByID provides a mock function with given fields: ctx, id func (_m *Orchestrator) GetOperationByID(ctx context.Context, id string) (*core.Operation, error) { ret := _m.Called(ctx, id) diff --git a/pkg/database/plugin.go b/pkg/database/plugin.go index 0316cdb58b..f0aee3dff9 100644 --- a/pkg/database/plugin.go +++ b/pkg/database/plugin.go @@ -71,9 +71,6 @@ type iNamespaceCollection interface { // GetNamespaceByID - Get a namespace by ID GetNamespaceByID(ctx context.Context, id *fftypes.UUID) (namespace *core.Namespace, err error) - - // GetNamespaces - Get namespaces - GetNamespaces(ctx context.Context, filter Filter) (namespaces []*core.Namespace, res *FilterResult, err error) } type iMessageCollection interface { @@ -702,17 +699,6 @@ type Capabilities struct { Concurrency bool } -// NamespaceQueryFactory filter fields for namespaces -var NamespaceQueryFactory = &queryFields{ - "id": &UUIDField{}, - "message": &UUIDField{}, - "type": &StringField{}, - "name": &StringField{}, - "description": &StringField{}, - "created": &TimeField{}, - "confirmed": &TimeField{}, -} - // MessageQueryFactory filter fields for messages var MessageQueryFactory = &queryFields{ "id": &UUIDField{}, From 4cd08bb8bd934e839118cb5ea0670a1b738d5db0 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Tue, 7 Jun 2022 14:11:09 -0400 Subject: [PATCH 15/33] Organize plugins onto child structs Signed-off-by: Andrew Richardson --- internal/namespace/manager.go | 196 ++++++++++----------- internal/namespace/manager_test.go | 50 +++--- internal/orchestrator/chart.go | 2 +- internal/orchestrator/data_query.go | 60 +++---- internal/orchestrator/orchestrator.go | 144 ++++++++------- internal/orchestrator/orchestrator_test.go | 44 +++-- internal/orchestrator/status.go | 22 +-- internal/orchestrator/subscriptions.go | 6 +- internal/orchestrator/txn_status.go | 8 +- 9 files changed, 267 insertions(+), 265 deletions(-) diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index 94ab1b8962..08964cae88 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -68,23 +68,26 @@ type namespace struct { description string orchestrator orchestrator.Orchestrator config orchestrator.Config + plugins orchestrator.Plugins } type namespaceManager struct { - ctx context.Context - cancelCtx context.CancelFunc - pluginNames map[string]bool + ctx context.Context + cancelCtx context.CancelFunc + namespaces map[string]*namespace + pluginNames map[string]bool + plugins struct { + blockchain map[string]orchestrator.BlockchainPlugin + identity map[string]orchestrator.IdentityPlugin + database map[string]orchestrator.DatabasePlugin + sharedstorage map[string]orchestrator.SharedStoragePlugin + dataexchange map[string]orchestrator.DataExchangePlugin + tokens map[string]orchestrator.TokensPlugin + } + metricsEnabled bool metrics metrics.Manager - blockchains map[string]orchestrator.BlockchainPlugin - identities map[string]orchestrator.IdentityPlugin - databases map[string]orchestrator.DatabasePlugin - sharedstorages map[string]orchestrator.SharedStoragePlugin - dataexchanges map[string]orchestrator.DataexchangePlugin - tokens map[string]orchestrator.TokensPlugin adminEvents adminevents.Manager - namespaces map[string]*namespace utOrchestrator orchestrator.Orchestrator - metricsEnabled bool } func NewNamespaceManager(withDefaults bool) Manager { @@ -128,7 +131,7 @@ func (nm *namespaceManager) Init(ctx context.Context, cancelCtx context.CancelFu for name, ns := range nm.namespaces { or := nm.utOrchestrator if or == nil { - or = orchestrator.NewOrchestrator(name, ns.config, nm.metrics, nm.adminEvents) + or = orchestrator.NewOrchestrator(name, ns.config, ns.plugins, nm.metrics, nm.adminEvents) } if err = or.Init(ctx, cancelCtx); err != nil { return err @@ -164,8 +167,8 @@ func (nm *namespaceManager) loadPlugins(ctx context.Context) (err error) { nm.metrics = metrics.NewMetricsManager(ctx) } - if nm.databases == nil { - nm.databases, err = nm.getDatabasePlugins(ctx) + if nm.plugins.database == nil { + nm.plugins.database, err = nm.getDatabasePlugins(ctx) if err != nil { return err } @@ -175,36 +178,36 @@ func (nm *namespaceManager) loadPlugins(ctx context.Context) (err error) { nm.adminEvents = adminevents.NewAdminEventManager(ctx) } - if nm.identities == nil { - nm.identities, err = nm.getIdentityPlugins(ctx) + if nm.plugins.identity == nil { + nm.plugins.identity, err = nm.getIdentityPlugins(ctx) if err != nil { return err } } - if nm.blockchains == nil { - nm.blockchains, err = nm.getBlockchainPlugins(ctx) + if nm.plugins.blockchain == nil { + nm.plugins.blockchain, err = nm.getBlockchainPlugins(ctx) if err != nil { return err } } - if nm.sharedstorages == nil { - nm.sharedstorages, err = nm.getSharedStoragePlugins(ctx) + if nm.plugins.sharedstorage == nil { + nm.plugins.sharedstorage, err = nm.getSharedStoragePlugins(ctx) if err != nil { return err } } - if nm.dataexchanges == nil { - nm.dataexchanges, err = nm.getDataExchangePlugins(ctx) + if nm.plugins.dataexchange == nil { + nm.plugins.dataexchange, err = nm.getDataExchangePlugins(ctx) if err != nil { return err } } - if nm.tokens == nil { - nm.tokens, err = nm.getTokensPlugins(ctx) + if nm.plugins.tokens == nil { + nm.plugins.tokens, err = nm.getTokensPlugins(ctx) if err != nil { return err } @@ -330,8 +333,8 @@ func (nm *namespaceManager) validatePluginConfig(ctx context.Context, config con return name, pluginType, nil } -func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins map[string]orchestrator.DataexchangePlugin, err error) { - plugins = make(map[string]orchestrator.DataexchangePlugin) +func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins map[string]orchestrator.DataExchangePlugin, err error) { + plugins = make(map[string]orchestrator.DataExchangePlugin) dxConfigArraySize := dataexchangeConfig.ArraySize() for i := 0; i < dxConfigArraySize; i++ { config := dataexchangeConfig.ArrayEntry(i) @@ -345,7 +348,7 @@ func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins return nil, err } - plugins[name] = orchestrator.DataexchangePlugin{ + plugins[name] = orchestrator.DataExchangePlugin{ Name: name, Plugin: plugin, Config: config.SubSection(pluginType), @@ -361,7 +364,7 @@ func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins } name := "dataexchange_0" - plugins[name] = orchestrator.DataexchangePlugin{ + plugins[name] = orchestrator.DataExchangePlugin{ Name: name, Plugin: plugin, Config: deprecatedDataexchangeConfig.SubSection(pluginType), @@ -539,155 +542,144 @@ func (nm *namespaceManager) loadNamespace(ctx context.Context, name string, inde pluginsRaw := conf.Get(coreconfig.NamespacePlugins) plugins := conf.GetStringSlice(coreconfig.NamespacePlugins) if pluginsRaw == nil { - for plugin := range nm.blockchains { + for plugin := range nm.plugins.blockchain { plugins = append(plugins, plugin) } - for plugin := range nm.dataexchanges { + for plugin := range nm.plugins.dataexchange { plugins = append(plugins, plugin) } - for plugin := range nm.sharedstorages { + for plugin := range nm.plugins.sharedstorage { plugins = append(plugins, plugin) } - for plugin := range nm.databases { + for plugin := range nm.plugins.database { plugins = append(plugins, plugin) } - for plugin := range nm.identities { + for plugin := range nm.plugins.identity { plugins = append(plugins, plugin) } - for plugin := range nm.tokens { + for plugin := range nm.plugins.tokens { plugins = append(plugins, plugin) } } config := orchestrator.Config{ DefaultKey: conf.GetString(coreconfig.NamespaceDefaultKey), - Tokens: make(map[string]orchestrator.TokensPlugin), } - + var p *orchestrator.Plugins if multiparty.(bool) { - config.Multiparty = orchestrator.MultipartyConfig{ - Enabled: true, - OrgName: orgName, - OrgKey: orgKey, - OrgDesc: orgDesc, - } - err = nm.validateMultiPartyConfig(ctx, name, &config, plugins) + config.Multiparty.Enabled = true + config.Multiparty.OrgName = orgName + config.Multiparty.OrgKey = orgKey + config.Multiparty.OrgDesc = orgDesc + p, err = nm.validateMultiPartyConfig(ctx, name, plugins) } else { - err = nm.validateGatewayConfig(ctx, name, &config, plugins) + p, err = nm.validateGatewayConfig(ctx, name, plugins) } if err == nil { nm.namespaces[name] = &namespace{ description: conf.GetString(coreconfig.NamespaceDescription), config: config, + plugins: *p, } } return err } -func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name string, config *orchestrator.Config, plugins []string) error { - var dbPlugin bool - var ssPlugin bool - var dxPlugin bool - var bcPlugin bool - +func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name string, plugins []string) (*orchestrator.Plugins, error) { + var result orchestrator.Plugins for _, pluginName := range plugins { - if instance, ok := nm.blockchains[pluginName]; ok { - if bcPlugin { - return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") + if instance, ok := nm.plugins.blockchain[pluginName]; ok { + if result.Blockchain.Plugin != nil { + return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") } - bcPlugin = true - config.Blockchain = instance + result.Blockchain = instance continue } - if instance, ok := nm.dataexchanges[pluginName]; ok { - if dxPlugin { - return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "dataexchange") + if instance, ok := nm.plugins.dataexchange[pluginName]; ok { + if result.DataExchange.Plugin != nil { + return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "dataexchange") } - dxPlugin = true - config.Dataexchange = instance + result.DataExchange = instance continue } - if instance, ok := nm.sharedstorages[pluginName]; ok { - if ssPlugin { - return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "sharedstorage") + if instance, ok := nm.plugins.sharedstorage[pluginName]; ok { + if result.SharedStorage.Plugin != nil { + return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "sharedstorage") } - ssPlugin = true - config.Sharedstorage = instance + result.SharedStorage = instance continue } - if instance, ok := nm.databases[pluginName]; ok { - if dbPlugin { - return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") + if instance, ok := nm.plugins.database[pluginName]; ok { + if result.Database.Plugin != nil { + return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") } - dbPlugin = true - config.Database = instance + result.Database = instance continue } - if instance, ok := nm.tokens[pluginName]; ok { - config.Tokens[pluginName] = instance + if instance, ok := nm.plugins.tokens[pluginName]; ok { + result.Tokens = append(result.Tokens, instance) continue } - if instance, ok := nm.identities[pluginName]; ok { - config.Identity = instance + if instance, ok := nm.plugins.identity[pluginName]; ok { + result.Identity = instance continue } - return i18n.NewError(ctx, coremsgs.MsgNamespaceUnknownPlugin, name, pluginName) + return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceUnknownPlugin, name, pluginName) } - if !dbPlugin || !ssPlugin || !dxPlugin || !bcPlugin { - return i18n.NewError(ctx, coremsgs.MsgNamespaceMultipartyConfiguration, name) + if result.Database.Plugin == nil || + result.SharedStorage.Plugin == nil || + result.DataExchange.Plugin == nil || + result.Blockchain.Plugin == nil { + return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceMultipartyConfiguration, name) } - return nil + return &result, nil } -func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name string, config *orchestrator.Config, plugins []string) error { - var dbPlugin bool - var bcPlugin bool - +func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name string, plugins []string) (*orchestrator.Plugins, error) { + var result orchestrator.Plugins for _, pluginName := range plugins { - if instance, ok := nm.blockchains[pluginName]; ok { - if bcPlugin { - return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") + if instance, ok := nm.plugins.blockchain[pluginName]; ok { + if result.Blockchain.Plugin != nil { + return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") } - bcPlugin = true - config.Blockchain = instance + result.Blockchain = instance continue } - if _, ok := nm.dataexchanges[pluginName]; ok { - return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayInvalidPlugins, name) + if _, ok := nm.plugins.dataexchange[pluginName]; ok { + return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayInvalidPlugins, name) } - if _, ok := nm.sharedstorages[pluginName]; ok { - return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayInvalidPlugins, name) + if _, ok := nm.plugins.sharedstorage[pluginName]; ok { + return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayInvalidPlugins, name) } - if instance, ok := nm.databases[pluginName]; ok { - if dbPlugin { - return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") + if instance, ok := nm.plugins.database[pluginName]; ok { + if result.Database.Plugin != nil { + return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") } - dbPlugin = true - config.Database = instance + result.Database = instance continue } - if instance, ok := nm.tokens[pluginName]; ok { - config.Tokens[pluginName] = instance + if instance, ok := nm.plugins.tokens[pluginName]; ok { + result.Tokens = append(result.Tokens, instance) continue } - return i18n.NewError(ctx, coremsgs.MsgNamespaceUnknownPlugin, name, pluginName) + return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceUnknownPlugin, name, pluginName) } - if !dbPlugin { - return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayNoDB, name) + if result.Database.Plugin == nil { + return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayNoDB, name) } - return nil + return &result, nil } func (nm *namespaceManager) AdminEvents() adminevents.Manager { diff --git a/internal/namespace/manager_test.go b/internal/namespace/manager_test.go index 75e3e217e6..7bef12314e 100644 --- a/internal/namespace/manager_test.go +++ b/internal/namespace/manager_test.go @@ -68,26 +68,26 @@ func newTestNamespaceManager(resetConfig bool) *testNamespaceManager { namespaceManager: namespaceManager{ namespaces: make(map[string]*namespace), pluginNames: make(map[string]bool), - blockchains: map[string]orchestrator.BlockchainPlugin{ - "ethereum": {Plugin: &blockchainmocks.Plugin{}}, - }, - databases: map[string]orchestrator.DatabasePlugin{ - "postgres": {Plugin: &databasemocks.Plugin{}}, - }, - dataexchanges: map[string]orchestrator.DataexchangePlugin{ - "ffdx": {Plugin: &dataexchangemocks.Plugin{}}, - }, - sharedstorages: map[string]orchestrator.SharedStoragePlugin{ - "ipfs": {Plugin: &sharedstoragemocks.Plugin{}}, - }, - identities: map[string]orchestrator.IdentityPlugin{ - "tbd": {Plugin: &identitymocks.Plugin{}}, - }, - tokens: map[string]orchestrator.TokensPlugin{ - "erc721": {Plugin: &tokenmocks.Plugin{}}, - }, }, } + nm.plugins.blockchain = map[string]orchestrator.BlockchainPlugin{ + "ethereum": {Plugin: &blockchainmocks.Plugin{}}, + } + nm.plugins.database = map[string]orchestrator.DatabasePlugin{ + "postgres": {Plugin: &databasemocks.Plugin{}}, + } + nm.plugins.dataexchange = map[string]orchestrator.DataExchangePlugin{ + "ffdx": {Plugin: &dataexchangemocks.Plugin{}}, + } + nm.plugins.sharedstorage = map[string]orchestrator.SharedStoragePlugin{ + "ipfs": {Plugin: &sharedstoragemocks.Plugin{}}, + } + nm.plugins.identity = map[string]orchestrator.IdentityPlugin{ + "tbd": {Plugin: &identitymocks.Plugin{}}, + } + nm.plugins.tokens = map[string]orchestrator.TokensPlugin{ + "erc721": {Plugin: &tokenmocks.Plugin{}}, + } nm.namespaceManager.metrics = nm.mmi nm.namespaceManager.adminEvents = nm.mae return nm @@ -118,7 +118,7 @@ func TestInitFail(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - mdi := nm.databases["postgres"].Plugin.(*databasemocks.Plugin) + mdi := nm.plugins.database["postgres"].Plugin.(*databasemocks.Plugin) mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) ctx, cancelCtx := context.WithCancel(context.Background()) @@ -174,7 +174,7 @@ func TestDatabasePluginBadType(t *testing.T) { func TestDatabasePluginBadName(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - nm.databases = nil + nm.plugins.database = nil difactory.InitConfig(databaseConfig) config.Set("plugins.database", []fftypes.JSONObject{{}}) databaseConfig.AddKnownKey(coreconfig.PluginConfigName, "wrong////") @@ -209,7 +209,7 @@ func TestIdentityPluginBadType(t *testing.T) { func TestIdentityPluginNoType(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - nm.identities = nil + nm.plugins.identity = nil iifactory.InitConfig(identityConfig) identityConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") config.Set("plugins.identity", []fftypes.JSONObject{{}}) @@ -273,7 +273,7 @@ func TestBlockchainPluginNoType(t *testing.T) { func TestBlockchainPluginBadType(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - nm.blockchains = nil + nm.plugins.blockchain = nil bifactory.InitConfig(blockchainConfig) config.Set("plugins.blockchain", []fftypes.JSONObject{{}}) blockchainConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") @@ -327,7 +327,7 @@ func TestSharedStoragePluginNoType(t *testing.T) { func TestSharedStoragePluginBadType(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - nm.sharedstorages = nil + nm.plugins.sharedstorage = nil ssfactory.InitConfig(sharedstorageConfig) config.Set("plugins.sharedstorage", []fftypes.JSONObject{{}}) sharedstorageConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") @@ -381,7 +381,7 @@ func TestDataExchangePluginNoType(t *testing.T) { func TestDataExchangePluginBadType(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - nm.dataexchanges = nil + nm.plugins.dataexchange = nil dxfactory.InitConfig(dataexchangeConfig) config.Set("plugins.dataexchange", []fftypes.JSONObject{{}}) dataexchangeConfig.AddKnownKey(coreconfig.PluginConfigName, "flapflip") @@ -460,7 +460,7 @@ func TestTokensPluginNoType(t *testing.T) { func TestTokensPluginBadType(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) - nm.tokens = nil + nm.plugins.tokens = nil tifactory.InitConfig(tokensConfig) config.Set("plugins.tokens", []fftypes.JSONObject{{}}) tokensConfig.AddKnownKey(coreconfig.PluginConfigName, "erc20_erc721") diff --git a/internal/orchestrator/chart.go b/internal/orchestrator/chart.go index 31f4cefb33..dc47cc1a7c 100644 --- a/internal/orchestrator/chart.go +++ b/internal/orchestrator/chart.go @@ -49,7 +49,7 @@ func (or *orchestrator) GetChartHistogram(ctx context.Context, ns string, startT intervals := or.getHistogramIntervals(startTime, endTime, buckets) - histogram, err := or.database.GetChartHistogram(ctx, ns, intervals, collection) + histogram, err := or.database().GetChartHistogram(ctx, ns, intervals, collection) if err != nil { return nil, err } diff --git a/internal/orchestrator/data_query.go b/internal/orchestrator/data_query.go index 95ee0b317e..705af58ab8 100644 --- a/internal/orchestrator/data_query.go +++ b/internal/orchestrator/data_query.go @@ -50,7 +50,7 @@ func (or *orchestrator) verifyIDAndNamespace(ctx context.Context, ns, id string) } func (or *orchestrator) GetNamespace(ctx context.Context, ns string) (*core.Namespace, error) { - return or.database.GetNamespace(ctx, ns) + return or.database().GetNamespace(ctx, ns) } func (or *orchestrator) GetTransactionByID(ctx context.Context, ns, id string) (*core.Transaction, error) { @@ -58,7 +58,7 @@ func (or *orchestrator) GetTransactionByID(ctx context.Context, ns, id string) ( if err != nil { return nil, err } - tx, err := or.database.GetTransactionByID(ctx, u) + tx, err := or.database().GetTransactionByID(ctx, u) if err == nil && tx != nil { err = or.checkNamespace(ctx, ns, tx.Namespace) } @@ -75,7 +75,7 @@ func (or *orchestrator) GetTransactionOperations(ctx context.Context, ns, id str fb.Eq("tx", u), fb.Eq("namespace", ns), ) - return or.database.GetOperations(ctx, filter) + return or.database().GetOperations(ctx, filter) } func (or *orchestrator) getMessageByID(ctx context.Context, ns, id string) (*core.Message, error) { @@ -83,7 +83,7 @@ func (or *orchestrator) getMessageByID(ctx context.Context, ns, id string) (*cor if err != nil { return nil, err } - msg, err := or.database.GetMessageByID(ctx, u) + msg, err := or.database().GetMessageByID(ctx, u) if err == nil && msg == nil { return nil, i18n.NewError(ctx, coremsgs.Msg404NotFound) } @@ -126,7 +126,7 @@ func (or *orchestrator) GetBatchByID(ctx context.Context, ns, id string) (*core. if err != nil { return nil, err } - b, err := or.database.GetBatchByID(ctx, u) + b, err := or.database().GetBatchByID(ctx, u) if err == nil && b != nil { err = or.checkNamespace(ctx, ns, b.Namespace) } @@ -138,7 +138,7 @@ func (or *orchestrator) GetDataByID(ctx context.Context, ns, id string) (*core.D if err != nil { return nil, err } - d, err := or.database.GetDataByID(ctx, u, true) + d, err := or.database().GetDataByID(ctx, u, true) if err == nil && d != nil { err = or.checkNamespace(ctx, ns, d.Namespace) } @@ -150,7 +150,7 @@ func (or *orchestrator) GetDatatypeByID(ctx context.Context, ns, id string) (*co if err != nil { return nil, err } - dt, err := or.database.GetDatatypeByID(ctx, u) + dt, err := or.database().GetDatatypeByID(ctx, u) if err == nil && dt != nil { err = or.checkNamespace(ctx, ns, dt.Namespace) } @@ -164,7 +164,7 @@ func (or *orchestrator) GetDatatypeByName(ctx context.Context, ns, name, version if err := core.ValidateFFNameFieldNoUUID(ctx, name, "name"); err != nil { return nil, err } - dt, err := or.database.GetDatatypeByName(ctx, ns, name, version) + dt, err := or.database().GetDatatypeByName(ctx, ns, name, version) if err == nil && dt != nil { err = or.checkNamespace(ctx, ns, dt.Namespace) } @@ -176,7 +176,7 @@ func (or *orchestrator) GetOperationByIDNamespaced(ctx context.Context, ns, id s if err != nil { return nil, err } - o, err := or.database.GetOperationByID(ctx, u) + o, err := or.database().GetOperationByID(ctx, u) if err == nil && o != nil { err = or.checkNamespace(ctx, ns, o.Namespace) } @@ -188,7 +188,7 @@ func (or *orchestrator) GetOperationByID(ctx context.Context, id string) (*core. if err != nil { return nil, err } - return or.database.GetOperationByID(ctx, u) + return or.database().GetOperationByID(ctx, u) } func (or *orchestrator) GetEventByID(ctx context.Context, ns, id string) (*core.Event, error) { @@ -196,7 +196,7 @@ func (or *orchestrator) GetEventByID(ctx context.Context, ns, id string) (*core. if err != nil { return nil, err } - e, err := or.database.GetEventByID(ctx, u) + e, err := or.database().GetEventByID(ctx, u) if err == nil && e != nil { err = or.checkNamespace(ctx, ns, e.Namespace) } @@ -209,17 +209,17 @@ func (or *orchestrator) scopeNS(ns string, filter database.AndFilter) database.A func (or *orchestrator) GetTransactions(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Transaction, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.GetTransactions(ctx, filter) + return or.database().GetTransactions(ctx, filter) } func (or *orchestrator) GetMessages(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Message, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.GetMessages(ctx, filter) + return or.database().GetMessages(ctx, filter) } func (or *orchestrator) GetMessagesWithData(ctx context.Context, ns string, filter database.AndFilter) ([]*core.MessageInOut, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - msgs, fr, err := or.database.GetMessages(ctx, filter) + msgs, fr, err := or.database().GetMessages(ctx, filter) if err != nil { return nil, nil, err } @@ -251,7 +251,7 @@ func (or *orchestrator) getMessageTransactionID(ctx context.Context, ns, id stri if msg.BatchID == nil { return nil, i18n.NewError(ctx, coremsgs.MsgBatchNotSet) } - batch, err := or.database.GetBatchByID(ctx, msg.BatchID) + batch, err := or.database().GetBatchByID(ctx, msg.BatchID) if err != nil { return nil, err } @@ -273,7 +273,7 @@ func (or *orchestrator) GetMessageTransaction(ctx context.Context, ns, id string if err != nil { return nil, err } - return or.database.GetTransactionByID(ctx, txID) + return or.database().GetTransactionByID(ctx, txID) } func (or *orchestrator) GetMessageOperations(ctx context.Context, ns, id string) ([]*core.Operation, *database.FilterResult, error) { @@ -282,7 +282,7 @@ func (or *orchestrator) GetMessageOperations(ctx context.Context, ns, id string) return nil, nil, err } filter := database.OperationQueryFactory.NewFilter(ctx).Eq("tx", txID) - return or.database.GetOperations(ctx, filter) + return or.database().GetOperations(ctx, filter) } func (or *orchestrator) GetMessageEvents(ctx context.Context, ns, id string, filter database.AndFilter) ([]*core.Event, *database.FilterResult, error) { @@ -299,17 +299,17 @@ func (or *orchestrator) GetMessageEvents(ctx context.Context, ns, id string, fil } filter = filter.Condition(filter.Builder().In("reference", referencedIDs)) // Execute the filter - return or.database.GetEvents(ctx, filter) + return or.database().GetEvents(ctx, filter) } func (or *orchestrator) GetBatches(ctx context.Context, ns string, filter database.AndFilter) ([]*core.BatchPersisted, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.GetBatches(ctx, filter) + return or.database().GetBatches(ctx, filter) } func (or *orchestrator) GetData(ctx context.Context, ns string, filter database.AndFilter) (core.DataArray, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.GetData(ctx, filter) + return or.database().GetData(ctx, filter) } func (or *orchestrator) GetMessagesForData(ctx context.Context, ns, dataID string, filter database.AndFilter) ([]*core.Message, *database.FilterResult, error) { @@ -318,26 +318,26 @@ func (or *orchestrator) GetMessagesForData(ctx context.Context, ns, dataID strin if err != nil { return nil, nil, err } - return or.database.GetMessagesForData(ctx, u, filter) + return or.database().GetMessagesForData(ctx, u, filter) } func (or *orchestrator) GetDatatypes(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Datatype, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.GetDatatypes(ctx, filter) + return or.database().GetDatatypes(ctx, filter) } func (or *orchestrator) GetOperationsNamespaced(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Operation, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.GetOperations(ctx, filter) + return or.database().GetOperations(ctx, filter) } func (or *orchestrator) GetOperations(ctx context.Context, filter database.AndFilter) ([]*core.Operation, *database.FilterResult, error) { - return or.database.GetOperations(ctx, filter) + return or.database().GetOperations(ctx, filter) } func (or *orchestrator) GetEvents(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Event, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.GetEvents(ctx, filter) + return or.database().GetEvents(ctx, filter) } func (or *orchestrator) GetBlockchainEventByID(ctx context.Context, ns, id string) (*core.BlockchainEvent, error) { @@ -345,7 +345,7 @@ func (or *orchestrator) GetBlockchainEventByID(ctx context.Context, ns, id strin if err != nil { return nil, err } - be, err := or.database.GetBlockchainEventByID(ctx, u) + be, err := or.database().GetBlockchainEventByID(ctx, u) if err == nil && be != nil { err = or.checkNamespace(ctx, ns, be.Namespace) } @@ -353,7 +353,7 @@ func (or *orchestrator) GetBlockchainEventByID(ctx context.Context, ns, id strin } func (or *orchestrator) GetBlockchainEvents(ctx context.Context, ns string, filter database.AndFilter) ([]*core.BlockchainEvent, *database.FilterResult, error) { - return or.database.GetBlockchainEvents(ctx, or.scopeNS(ns, filter)) + return or.database().GetBlockchainEvents(ctx, or.scopeNS(ns, filter)) } func (or *orchestrator) GetTransactionBlockchainEvents(ctx context.Context, ns, id string) ([]*core.BlockchainEvent, *database.FilterResult, error) { @@ -366,16 +366,16 @@ func (or *orchestrator) GetTransactionBlockchainEvents(ctx context.Context, ns, fb.Eq("tx.id", u), fb.Eq("namespace", ns), ) - return or.database.GetBlockchainEvents(ctx, filter) + return or.database().GetBlockchainEvents(ctx, filter) } func (or *orchestrator) GetPins(ctx context.Context, filter database.AndFilter) ([]*core.Pin, *database.FilterResult, error) { - return or.database.GetPins(ctx, filter) + return or.database().GetPins(ctx, filter) } func (or *orchestrator) GetEventsWithReferences(ctx context.Context, ns string, filter database.AndFilter) ([]*core.EnrichedEvent, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - events, fr, err := or.database.GetEvents(ctx, filter) + events, fr, err := or.database().GetEvents(ctx, filter) if err != nil { return nil, nil, err } diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 227f4d948a..a1978d3bb6 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -131,7 +131,7 @@ type DatabasePlugin struct { Config config.Section } -type DataexchangePlugin struct { +type DataExchangePlugin struct { Name string Plugin dataexchange.Plugin Config config.Section @@ -155,22 +155,23 @@ type IdentityPlugin struct { Config config.Section } -type MultipartyConfig struct { - Enabled bool - OrgName string - OrgDesc string - OrgKey string -} - -type Config struct { - DefaultKey string - Multiparty MultipartyConfig +type Plugins struct { Blockchain BlockchainPlugin Identity IdentityPlugin - Sharedstorage SharedStoragePlugin - Dataexchange DataexchangePlugin + SharedStorage SharedStoragePlugin + DataExchange DataExchangePlugin Database DatabasePlugin - Tokens map[string]TokensPlugin + Tokens []TokensPlugin +} + +type Config struct { + DefaultKey string + Multiparty struct { + Enabled bool + OrgName string + OrgDesc string + OrgKey string + } } type orchestrator struct { @@ -179,11 +180,8 @@ type orchestrator struct { started bool namespace string config Config - blockchain blockchain.Plugin + plugins Plugins identity identity.Manager - sharedstorage sharedstorage.Plugin - dataexchange dataexchange.Plugin - database database.Plugin events events.EventManager networkmap networkmap.Manager batch batch.Manager @@ -194,7 +192,6 @@ type orchestrator struct { syncasync syncasync.Bridge batchpin batchpin.Submitter assets assets.Manager - tokens map[string]tokens.Plugin bc boundCallbacks contracts contracts.Manager node *fftypes.UUID @@ -205,23 +202,14 @@ type orchestrator struct { adminEvents adminevents.Manager } -func NewOrchestrator(ns string, config Config, metrics metrics.Manager, adminEvents adminevents.Manager) Orchestrator { - or := &orchestrator{ - namespace: ns, - config: config, - blockchain: config.Blockchain.Plugin, - database: config.Database.Plugin, - sharedstorage: config.Sharedstorage.Plugin, - dataexchange: config.Dataexchange.Plugin, - tokens: make(map[string]tokens.Plugin, len(config.Tokens)), - metrics: metrics, - adminEvents: adminEvents, - } - for name, ti := range config.Tokens { - or.tokens[name] = ti.Plugin +func NewOrchestrator(ns string, config Config, plugins Plugins, metrics metrics.Manager, adminEvents adminevents.Manager) Orchestrator { + return &orchestrator{ + namespace: ns, + config: config, + plugins: plugins, + metrics: metrics, + adminEvents: adminEvents, } - - return or } func (or *orchestrator) Init(ctx context.Context, cancelCtx context.CancelFunc) (err error) { @@ -232,17 +220,41 @@ func (or *orchestrator) Init(ctx context.Context, cancelCtx context.CancelFunc) err = or.initComponents(ctx) } // Bind together the blockchain interface callbacks, with the events manager - or.bc.bi = or.blockchain + or.bc.bi = or.plugins.Blockchain.Plugin or.bc.ei = or.events - or.bc.dx = or.dataexchange - or.bc.ss = or.sharedstorage + or.bc.dx = or.plugins.DataExchange.Plugin + or.bc.ss = or.plugins.SharedStorage.Plugin or.bc.om = or.operations return err } +func (or *orchestrator) database() database.Plugin { + return or.plugins.Database.Plugin +} + +func (or *orchestrator) blockchain() blockchain.Plugin { + return or.plugins.Blockchain.Plugin +} + +func (or *orchestrator) dataexchange() dataexchange.Plugin { + return or.plugins.DataExchange.Plugin +} + +func (or *orchestrator) sharedstorage() sharedstorage.Plugin { + return or.plugins.SharedStorage.Plugin +} + +func (or *orchestrator) tokens() map[string]tokens.Plugin { + result := make(map[string]tokens.Plugin, len(or.plugins.Tokens)) + for _, plugin := range or.plugins.Tokens { + result[plugin.Name] = plugin.Plugin + } + return result +} + func (or *orchestrator) Start() (err error) { var ns *core.Namespace - ns, err = or.database.GetNamespace(or.ctx, or.namespace) + ns, err = or.database().GetNamespace(or.ctx, or.namespace) if err == nil { if ns == nil { ns = &core.Namespace{ @@ -250,13 +262,13 @@ func (or *orchestrator) Start() (err error) { Created: fftypes.Now(), } } - err = or.blockchain.ConfigureContract(or.ctx, &ns.Contracts) + err = or.blockchain().ConfigureContract(or.ctx, &ns.Contracts) } if err == nil { - err = or.blockchain.Start() + err = or.blockchain().Start() } if err == nil { - err = or.database.UpsertNamespace(or.ctx, ns, true) + err = or.database().UpsertNamespace(or.ctx, ns, true) } if err == nil { err = or.batch.Start() @@ -277,7 +289,7 @@ func (or *orchestrator) Start() (err error) { err = or.sharedDownload.Start() } if err == nil { - for _, el := range or.tokens { + for _, el := range or.tokens() { if err = el.Start(); err != nil { break } @@ -355,18 +367,18 @@ func (or *orchestrator) Operations() operations.Manager { } func (or *orchestrator) initPlugins(ctx context.Context) (err error) { - err = or.database.Init(ctx, or.config.Database.Config, or) + err = or.plugins.Database.Plugin.Init(ctx, or.plugins.Database.Config, or) if err != nil { return err } - err = or.blockchain.Init(ctx, or.config.Blockchain.Config, &or.bc, or.metrics) + err = or.plugins.Blockchain.Plugin.Init(ctx, or.plugins.Blockchain.Config, &or.bc, or.metrics) if err != nil { return err } fb := database.IdentityQueryFactory.NewFilter(ctx) - nodes, _, err := or.database.GetIdentities(ctx, fb.And( + nodes, _, err := or.database().GetIdentities(ctx, fb.And( fb.Eq("type", core.IdentityTypeNode), )) if err != nil { @@ -377,18 +389,18 @@ func (or *orchestrator) initPlugins(ctx context.Context) (err error) { nodeInfo[i] = node.Profile } - err = or.dataexchange.Init(ctx, or.config.Dataexchange.Config, nodeInfo, &or.bc) + err = or.plugins.DataExchange.Plugin.Init(ctx, or.plugins.DataExchange.Config, nodeInfo, &or.bc) if err != nil { return err } - err = or.sharedstorage.Init(ctx, or.config.Sharedstorage.Config, &or.bc) + err = or.plugins.SharedStorage.Plugin.Init(ctx, or.plugins.SharedStorage.Config, &or.bc) if err != nil { return err } - for name, token := range or.tokens { - err = token.Init(ctx, name, or.config.Tokens[name].Config, &or.bc) + for _, token := range or.plugins.Tokens { + err = token.Plugin.Init(ctx, token.Name, token.Config, &or.bc) } return err @@ -397,86 +409,86 @@ func (or *orchestrator) initPlugins(ctx context.Context) (err error) { func (or *orchestrator) initComponents(ctx context.Context) (err error) { if or.data == nil { - or.data, err = data.NewDataManager(ctx, or.database, or.sharedstorage, or.dataexchange) + or.data, err = data.NewDataManager(ctx, or.database(), or.sharedstorage(), or.dataexchange()) if err != nil { return err } } if or.txHelper == nil { - or.txHelper = txcommon.NewTransactionHelper(or.database, or.data) + or.txHelper = txcommon.NewTransactionHelper(or.database(), or.data) } if or.identity == nil { - or.identity, err = identity.NewIdentityManager(ctx, or.config.DefaultKey, or.config.Multiparty.OrgName, or.config.Multiparty.OrgKey, or.database, or.blockchain, or.data) + or.identity, err = identity.NewIdentityManager(ctx, or.config.DefaultKey, or.config.Multiparty.OrgName, or.config.Multiparty.OrgKey, or.database(), or.blockchain(), or.data) if err != nil { return err } } if or.batch == nil { - or.batch, err = batch.NewBatchManager(ctx, or, or.database, or.data, or.txHelper) + or.batch, err = batch.NewBatchManager(ctx, or, or.database(), or.data, or.txHelper) if err != nil { return err } } if or.operations == nil { - if or.operations, err = operations.NewOperationsManager(ctx, or.database, or.txHelper); err != nil { + if or.operations, err = operations.NewOperationsManager(ctx, or.database(), or.txHelper); err != nil { return err } } - or.syncasync = syncasync.NewSyncAsyncBridge(ctx, or.database, or.data) + or.syncasync = syncasync.NewSyncAsyncBridge(ctx, or.database(), or.data) if or.batchpin == nil { - if or.batchpin, err = batchpin.NewBatchPinSubmitter(ctx, or.database, or.identity, or.blockchain, or.metrics, or.operations); err != nil { + if or.batchpin, err = batchpin.NewBatchPinSubmitter(ctx, or.database(), or.identity, or.blockchain(), or.metrics, or.operations); err != nil { return err } } if or.messaging == nil { - if or.messaging, err = privatemessaging.NewPrivateMessaging(ctx, or.database, or.identity, or.dataexchange, or.blockchain, or.batch, or.data, or.syncasync, or.batchpin, or.metrics, or.operations); err != nil { + if or.messaging, err = privatemessaging.NewPrivateMessaging(ctx, or.database(), or.identity, or.dataexchange(), or.blockchain(), or.batch, or.data, or.syncasync, or.batchpin, or.metrics, or.operations); err != nil { return err } } if or.broadcast == nil { - if or.broadcast, err = broadcast.NewBroadcastManager(ctx, or.database, or.identity, or.data, or.blockchain, or.dataexchange, or.sharedstorage, or.batch, or.syncasync, or.batchpin, or.metrics, or.operations); err != nil { + if or.broadcast, err = broadcast.NewBroadcastManager(ctx, or.database(), or.identity, or.data, or.blockchain(), or.dataexchange(), or.sharedstorage(), or.batch, or.syncasync, or.batchpin, or.metrics, or.operations); err != nil { return err } } if or.assets == nil { - or.assets, err = assets.NewAssetManager(ctx, or.database, or.identity, or.data, or.syncasync, or.broadcast, or.messaging, or.tokens, or.metrics, or.operations, or.txHelper) + or.assets, err = assets.NewAssetManager(ctx, or.database(), or.identity, or.data, or.syncasync, or.broadcast, or.messaging, or.tokens(), or.metrics, or.operations, or.txHelper) if err != nil { return err } } if or.contracts == nil { - or.contracts, err = contracts.NewContractManager(ctx, or.database, or.broadcast, or.identity, or.blockchain, or.operations, or.txHelper, or.syncasync) + or.contracts, err = contracts.NewContractManager(ctx, or.database(), or.broadcast, or.identity, or.blockchain(), or.operations, or.txHelper, or.syncasync) if err != nil { return err } } if or.definitions == nil { - or.definitions, err = definitions.NewDefinitionHandler(ctx, or.database, or.blockchain, or.dataexchange, or.data, or.identity, or.assets, or.contracts) + or.definitions, err = definitions.NewDefinitionHandler(ctx, or.database(), or.blockchain(), or.dataexchange(), or.data, or.identity, or.assets, or.contracts) if err != nil { return err } } if or.sharedDownload == nil { - or.sharedDownload, err = shareddownload.NewDownloadManager(ctx, or.database, or.sharedstorage, or.dataexchange, or.operations, &or.bc) + or.sharedDownload, err = shareddownload.NewDownloadManager(ctx, or.database(), or.sharedstorage(), or.dataexchange(), or.operations, &or.bc) if err != nil { return err } } if or.events == nil { - or.events, err = events.NewEventManager(ctx, or.namespace, or, or.sharedstorage, or.database, or.blockchain, or.identity, or.definitions, or.data, or.broadcast, or.messaging, or.assets, or.sharedDownload, or.metrics, or.txHelper) + or.events, err = events.NewEventManager(ctx, or.namespace, or, or.sharedstorage(), or.database(), or.blockchain(), or.identity, or.definitions, or.data, or.broadcast, or.messaging, or.assets, or.sharedDownload, or.metrics, or.txHelper) if err != nil { return err } @@ -485,7 +497,7 @@ func (or *orchestrator) initComponents(ctx context.Context) (err error) { or.syncasync.Init(or.events) if or.networkmap == nil { - or.networkmap, err = networkmap.NewNetworkMap(ctx, or.config.Multiparty.OrgName, or.config.Multiparty.OrgDesc, or.database, or.data, or.broadcast, or.dataexchange, or.identity, or.syncasync) + or.networkmap, err = networkmap.NewNetworkMap(ctx, or.config.Multiparty.OrgName, or.config.Multiparty.OrgDesc, or.database(), or.data, or.broadcast, or.dataexchange(), or.identity, or.syncasync) } return err } @@ -503,5 +515,5 @@ func (or *orchestrator) SubmitNetworkAction(ctx context.Context, ns string, acti } else { return i18n.NewError(ctx, coremsgs.MsgUnrecognizedNetworkAction, action.Type) } - return or.blockchain.SubmitNetworkAction(ctx, fftypes.NewUUID(), key, action.Type) + return or.blockchain().SubmitNetworkAction(ctx, fftypes.NewUUID(), key, action.Type) } diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index c3bc502d08..7289230e59 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -46,7 +46,6 @@ import ( "github.com/hyperledger/firefly/mocks/tokenmocks" "github.com/hyperledger/firefly/mocks/txcommonmocks" "github.com/hyperledger/firefly/pkg/core" - "github.com/hyperledger/firefly/pkg/tokens" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) @@ -137,20 +136,15 @@ func newTestOrchestrator() *testOrchestrator { mae: &admineventsmocks.Manager{}, mdh: &definitionsmocks.DefinitionHandler{}, } - tor.orchestrator.database = tor.mdi tor.orchestrator.data = tor.mdm tor.orchestrator.batch = tor.mba tor.orchestrator.broadcast = tor.mbm tor.orchestrator.events = tor.mem tor.orchestrator.networkmap = tor.mnm - tor.orchestrator.sharedstorage = tor.mps tor.orchestrator.messaging = tor.mpm tor.orchestrator.identity = tor.mim - tor.orchestrator.dataexchange = tor.mdx tor.orchestrator.assets = tor.mam tor.orchestrator.contracts = tor.mcm - tor.orchestrator.tokens = map[string]tokens.Plugin{"token": tor.mti} - tor.orchestrator.blockchain = tor.mbi tor.orchestrator.metrics = tor.mmi tor.orchestrator.operations = tor.mom tor.orchestrator.batchpin = tor.mbp @@ -158,6 +152,11 @@ func newTestOrchestrator() *testOrchestrator { tor.orchestrator.adminEvents = tor.mae tor.orchestrator.txHelper = tor.mth tor.orchestrator.definitions = tor.mdh + tor.orchestrator.plugins.Blockchain.Plugin = tor.mbi + tor.orchestrator.plugins.SharedStorage.Plugin = tor.mps + tor.orchestrator.plugins.DataExchange.Plugin = tor.mdx + tor.orchestrator.plugins.Database.Plugin = tor.mdi + tor.orchestrator.plugins.Tokens = []TokensPlugin{{Name: "token", Plugin: tor.mti}} tor.mdi.On("Name").Return("mock-di").Maybe() tor.mem.On("Name").Return("mock-ei").Maybe() tor.mps.On("Name").Return("mock-ps").Maybe() @@ -174,9 +173,8 @@ func newTestOrchestrator() *testOrchestrator { func TestNewOrchestrator(t *testing.T) { or := NewOrchestrator( "ns1", - Config{ - Tokens: map[string]TokensPlugin{"token": {Plugin: &tokenmocks.Plugin{}}}, - }, + Config{}, + Plugins{}, &metricsmocks.Manager{}, &admineventsmocks.Manager{}, ) @@ -268,7 +266,7 @@ func TestInitAllPluginsOK(t *testing.T) { func TestInitMessagingComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.messaging = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -277,7 +275,7 @@ func TestInitMessagingComponentFail(t *testing.T) { func TestInitEventsComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.events = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -286,7 +284,7 @@ func TestInitEventsComponentFail(t *testing.T) { func TestInitNetworkMapComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.networkmap = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -295,7 +293,7 @@ func TestInitNetworkMapComponentFail(t *testing.T) { func TestInitOperationComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.operations = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -304,7 +302,7 @@ func TestInitOperationComponentFail(t *testing.T) { func TestInitSharedStorageDownloadComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.sharedDownload = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -313,7 +311,7 @@ func TestInitSharedStorageDownloadComponentFail(t *testing.T) { func TestInitBatchComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.batch = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -322,7 +320,7 @@ func TestInitBatchComponentFail(t *testing.T) { func TestInitBroadcastComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.broadcast = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -331,7 +329,7 @@ func TestInitBroadcastComponentFail(t *testing.T) { func TestInitDataComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.data = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -340,7 +338,7 @@ func TestInitDataComponentFail(t *testing.T) { func TestInitIdentityComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.identity = nil or.txHelper = nil err := or.initComponents(context.Background()) @@ -350,7 +348,7 @@ func TestInitIdentityComponentFail(t *testing.T) { func TestInitAssetsComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.assets = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -359,7 +357,7 @@ func TestInitAssetsComponentFail(t *testing.T) { func TestInitContractsComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.contracts = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -368,7 +366,7 @@ func TestInitContractsComponentFail(t *testing.T) { func TestInitDefinitionsComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.definitions = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -377,7 +375,7 @@ func TestInitDefinitionsComponentFail(t *testing.T) { func TestInitBatchPinComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.batchpin = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) @@ -386,7 +384,7 @@ func TestInitBatchPinComponentFail(t *testing.T) { func TestInitOperationsComponentFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.database = nil + or.plugins.Database.Plugin = nil or.operations = nil err := or.initComponents(context.Background()) assert.Regexp(t, "FF10128", err) diff --git a/internal/orchestrator/status.go b/internal/orchestrator/status.go index fd98695d62..398ab15048 100644 --- a/internal/orchestrator/status.go +++ b/internal/orchestrator/status.go @@ -31,35 +31,35 @@ import ( func (or *orchestrator) getPlugins() core.NodeStatusPlugins { // Plugins can have more than one name, so they must be iterated over tokensArray := make([]*core.NodeStatusPlugin, 0) - for name, plugin := range or.tokens { + for _, plugin := range or.plugins.Tokens { tokensArray = append(tokensArray, &core.NodeStatusPlugin{ - Name: name, - PluginType: plugin.Name(), + Name: plugin.Name, + PluginType: plugin.Plugin.Name(), }) } blockchainsArray := make([]*core.NodeStatusPlugin, 0) blockchainsArray = append(blockchainsArray, &core.NodeStatusPlugin{ - Name: or.config.Blockchain.Name, - PluginType: or.blockchain.Name(), + Name: or.plugins.Blockchain.Name, + PluginType: or.plugins.Blockchain.Plugin.Name(), }) databasesArray := make([]*core.NodeStatusPlugin, 0) databasesArray = append(databasesArray, &core.NodeStatusPlugin{ - Name: or.config.Database.Name, - PluginType: or.database.Name(), + Name: or.plugins.Database.Name, + PluginType: or.plugins.Database.Plugin.Name(), }) sharedstorageArray := make([]*core.NodeStatusPlugin, 0) sharedstorageArray = append(sharedstorageArray, &core.NodeStatusPlugin{ - Name: or.config.Sharedstorage.Name, - PluginType: or.sharedstorage.Name(), + Name: or.plugins.SharedStorage.Name, + PluginType: or.plugins.SharedStorage.Plugin.Name(), }) dataexchangeArray := make([]*core.NodeStatusPlugin, 0) dataexchangeArray = append(dataexchangeArray, &core.NodeStatusPlugin{ - Name: or.config.Dataexchange.Name, - PluginType: or.dataexchange.Name(), + Name: or.plugins.DataExchange.Name, + PluginType: or.plugins.DataExchange.Plugin.Name(), }) return core.NodeStatusPlugins{ diff --git a/internal/orchestrator/subscriptions.go b/internal/orchestrator/subscriptions.go index e882dc4f8a..fe5231e6e9 100644 --- a/internal/orchestrator/subscriptions.go +++ b/internal/orchestrator/subscriptions.go @@ -58,7 +58,7 @@ func (or *orchestrator) DeleteSubscription(ctx context.Context, ns, id string) e if err != nil { return err } - sub, err := or.database.GetSubscriptionByID(ctx, u) + sub, err := or.database().GetSubscriptionByID(ctx, u) if err != nil { return err } @@ -70,7 +70,7 @@ func (or *orchestrator) DeleteSubscription(ctx context.Context, ns, id string) e func (or *orchestrator) GetSubscriptions(ctx context.Context, ns string, filter database.AndFilter) ([]*core.Subscription, *database.FilterResult, error) { filter = or.scopeNS(ns, filter) - return or.database.GetSubscriptions(ctx, filter) + return or.database().GetSubscriptions(ctx, filter) } func (or *orchestrator) GetSubscriptionByID(ctx context.Context, ns, id string) (*core.Subscription, error) { @@ -78,5 +78,5 @@ func (or *orchestrator) GetSubscriptionByID(ctx context.Context, ns, id string) if err != nil { return nil, err } - return or.database.GetSubscriptionByID(ctx, u) + return or.database().GetSubscriptionByID(ctx, u) } diff --git a/internal/orchestrator/txn_status.go b/internal/orchestrator/txn_status.go index fac5fcd61f..3b20804860 100644 --- a/internal/orchestrator/txn_status.go +++ b/internal/orchestrator/txn_status.go @@ -101,7 +101,7 @@ func (or *orchestrator) GetTransactionStatus(ctx context.Context, ns, id string) updateStatus(result, core.OpStatusPending) } f := database.BatchQueryFactory.NewFilter(ctx) - switch batches, _, err := or.database.GetBatches(ctx, f.Eq("tx.id", id)); { + switch batches, _, err := or.database().GetBatches(ctx, f.Eq("tx.id", id)); { case err != nil: return nil, err case len(batches) == 0: @@ -120,7 +120,7 @@ func (or *orchestrator) GetTransactionStatus(ctx context.Context, ns, id string) case core.TransactionTypeTokenPool: // Note: no assumptions about blockchain events here (may or may not contain one) f := database.TokenPoolQueryFactory.NewFilter(ctx) - switch pools, _, err := or.database.GetTokenPools(ctx, f.Eq("tx.id", id)); { + switch pools, _, err := or.database().GetTokenPools(ctx, f.Eq("tx.id", id)); { case err != nil: return nil, err case len(pools) == 0: @@ -150,7 +150,7 @@ func (or *orchestrator) GetTransactionStatus(ctx context.Context, ns, id string) updateStatus(result, core.OpStatusPending) } f := database.TokenTransferQueryFactory.NewFilter(ctx) - switch transfers, _, err := or.database.GetTokenTransfers(ctx, f.Eq("tx.id", id)); { + switch transfers, _, err := or.database().GetTokenTransfers(ctx, f.Eq("tx.id", id)); { case err != nil: return nil, err case len(transfers) == 0: @@ -172,7 +172,7 @@ func (or *orchestrator) GetTransactionStatus(ctx context.Context, ns, id string) updateStatus(result, core.OpStatusPending) } f := database.TokenApprovalQueryFactory.NewFilter(ctx) - switch approvals, _, err := or.database.GetTokenApprovals(ctx, f.Eq("tx.id", id)); { + switch approvals, _, err := or.database().GetTokenApprovals(ctx, f.Eq("tx.id", id)); { case err != nil: return nil, err case len(approvals) == 0: From a07bd87737f96856077ff386fe8598a0d0439567 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Tue, 7 Jun 2022 15:09:59 -0400 Subject: [PATCH 16/33] Fix SPI routes to use proper namespaces Only the "get many" route for operations is broken now. Signed-off-by: Andrew Richardson --- internal/apiserver/route_get_namespace.go | 5 +- .../route_spi_get_namespace_by_name.go | 5 +- internal/apiserver/route_spi_get_op_by_id.go | 2 +- .../apiserver/route_spi_get_op_by_id_test.go | 5 +- internal/apiserver/route_spi_get_ops.go | 1 + internal/apiserver/route_spi_get_ops_test.go | 10 +- .../apiserver/route_spi_patch_op_by_id.go | 2 +- .../route_spi_patch_op_by_id_test.go | 8 +- internal/apiserver/routes.go | 12 +- internal/apiserver/server.go | 19 +++- internal/namespace/manager.go | 26 +++++ internal/namespace/manager_test.go | 106 ++++++++++++++++++ internal/operations/manager.go | 11 +- internal/operations/manager_test.go | 15 +-- mocks/namespacemocks/manager.go | 37 ++++++ mocks/operationmocks/manager.go | 10 +- 16 files changed, 221 insertions(+), 53 deletions(-) diff --git a/internal/apiserver/route_get_namespace.go b/internal/apiserver/route_get_namespace.go index 4d8c9fb7f1..bbc9c49cdb 100644 --- a/internal/apiserver/route_get_namespace.go +++ b/internal/apiserver/route_get_namespace.go @@ -39,8 +39,9 @@ var getNamespace = &ffapi.Route{ JSONOutputCodes: []int{http.StatusOK}, Extensions: &coreExtensions{ CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { - output, err = cr.or.GetNamespace(cr.ctx, extractNamespace(r.PP)) - return output, err + ns := r.PP["ns"] + or := cr.mgr.Orchestrator(ns) + return or.GetNamespace(cr.ctx, ns) }, }, } diff --git a/internal/apiserver/route_spi_get_namespace_by_name.go b/internal/apiserver/route_spi_get_namespace_by_name.go index 12e22ca29c..fd5bb6659a 100644 --- a/internal/apiserver/route_spi_get_namespace_by_name.go +++ b/internal/apiserver/route_spi_get_namespace_by_name.go @@ -38,8 +38,9 @@ var spiGetNamespaceByName = &ffapi.Route{ JSONOutputCodes: []int{http.StatusOK}, Extensions: &coreExtensions{ CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { - output, err = cr.or.GetNamespace(cr.ctx, extractNamespace(r.PP)) - return output, err + ns := r.PP["ns"] + or := cr.mgr.Orchestrator(ns) + return or.GetNamespace(cr.ctx, ns) }, }, } diff --git a/internal/apiserver/route_spi_get_op_by_id.go b/internal/apiserver/route_spi_get_op_by_id.go index 41732206f0..9f2b3cfa6c 100644 --- a/internal/apiserver/route_spi_get_op_by_id.go +++ b/internal/apiserver/route_spi_get_op_by_id.go @@ -38,7 +38,7 @@ var spiGetOpByID = &ffapi.Route{ JSONOutputCodes: []int{http.StatusOK}, Extensions: &coreExtensions{ CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { - output, err = cr.or.GetOperationByNamespacedID(cr.ctx, r.PP["nsopid"]) + output, err = cr.mgr.GetOperationByNamespacedID(cr.ctx, r.PP["nsopid"]) return output, err }, }, diff --git a/internal/apiserver/route_spi_get_op_by_id_test.go b/internal/apiserver/route_spi_get_op_by_id_test.go index 2adabea4cb..09e39ec304 100644 --- a/internal/apiserver/route_spi_get_op_by_id_test.go +++ b/internal/apiserver/route_spi_get_op_by_id_test.go @@ -26,12 +26,13 @@ import ( ) func TestSPIGetOperationByID(t *testing.T) { - o, r := newTestSPIServer() + mgr, _, as := newTestServer() + r := as.createAdminMuxRouter(mgr) req := httptest.NewRequest("GET", "/spi/v1/operations/ns1:0df3d864-2646-4e5d-8585-51eb154a8d23", nil) req.Header.Set("Content-Type", "application/json; charset=utf-8") res := httptest.NewRecorder() - o.On("GetOperationByNamespacedID", mock.Anything, "ns1:0df3d864-2646-4e5d-8585-51eb154a8d23"). + mgr.On("GetOperationByNamespacedID", mock.Anything, "ns1:0df3d864-2646-4e5d-8585-51eb154a8d23"). Return(&core.Operation{}, nil) r.ServeHTTP(res, req) diff --git a/internal/apiserver/route_spi_get_ops.go b/internal/apiserver/route_spi_get_ops.go index bda3a28d5f..5b0d4b9b0e 100644 --- a/internal/apiserver/route_spi_get_ops.go +++ b/internal/apiserver/route_spi_get_ops.go @@ -37,6 +37,7 @@ var spiGetOps = &ffapi.Route{ Extensions: &coreExtensions{ FilterFactory: database.OperationQueryFactory, CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { + // TODO: cr.or will be nil (this must be converted to a namespaced query) return filterResult(cr.or.GetOperations(cr.ctx, cr.filter)) }, }, diff --git a/internal/apiserver/route_spi_get_ops_test.go b/internal/apiserver/route_spi_get_ops_test.go index 139785ac30..7d6f5b26ad 100644 --- a/internal/apiserver/route_spi_get_ops_test.go +++ b/internal/apiserver/route_spi_get_ops_test.go @@ -20,20 +20,18 @@ import ( "net/http/httptest" "testing" - "github.com/hyperledger/firefly/pkg/core" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" ) func TestSPIGetOperations(t *testing.T) { - o, r := newTestSPIServer() + _, r := newTestSPIServer() req := httptest.NewRequest("GET", "/spi/v1/operations", nil) req.Header.Set("Content-Type", "application/json; charset=utf-8") res := httptest.NewRecorder() - o.On("GetOperations", mock.Anything, mock.Anything). - Return([]*core.Operation{}, nil, nil) - r.ServeHTTP(res, req) + assert.Panics(t, func() { + r.ServeHTTP(res, req) + }) assert.Equal(t, 200, res.Result().StatusCode) } diff --git a/internal/apiserver/route_spi_patch_op_by_id.go b/internal/apiserver/route_spi_patch_op_by_id.go index 2fea1e46e7..dc1c4880bc 100644 --- a/internal/apiserver/route_spi_patch_op_by_id.go +++ b/internal/apiserver/route_spi_patch_op_by_id.go @@ -38,7 +38,7 @@ var spiPatchOpByID = &ffapi.Route{ JSONOutputCodes: []int{http.StatusOK}, Extensions: &coreExtensions{ CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { - err = cr.or.Operations().ResolveOperationByNamespacedID(cr.ctx, r.PP["nsopid"], r.Input.(*core.OperationUpdateDTO)) + err = cr.mgr.ResolveOperationByNamespacedID(cr.ctx, r.PP["nsopid"], r.Input.(*core.OperationUpdateDTO)) return &core.EmptyInput{}, err }, }, diff --git a/internal/apiserver/route_spi_patch_op_by_id_test.go b/internal/apiserver/route_spi_patch_op_by_id_test.go index 4feabf6872..230d3240b3 100644 --- a/internal/apiserver/route_spi_patch_op_by_id_test.go +++ b/internal/apiserver/route_spi_patch_op_by_id_test.go @@ -21,20 +21,18 @@ import ( "net/http/httptest" "testing" - "github.com/hyperledger/firefly/mocks/operationmocks" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) func TestSPIPatchOperationByID(t *testing.T) { - o, r := newTestSPIServer() + mgr, _, as := newTestServer() + r := as.createAdminMuxRouter(mgr) req := httptest.NewRequest("PATCH", "/spi/v1/operations/ns1:0df3d864-2646-4e5d-8585-51eb154a8d23", bytes.NewReader([]byte("{}"))) req.Header.Set("Content-Type", "application/json; charset=utf-8") res := httptest.NewRecorder() - mop := &operationmocks.Manager{} - o.On("Operations").Return(mop) - mop.On("ResolveOperationByNamespacedID", mock.Anything, "ns1:0df3d864-2646-4e5d-8585-51eb154a8d23", mock.AnythingOfType("*core.OperationUpdateDTO")).Return(nil) + mgr.On("ResolveOperationByNamespacedID", mock.Anything, "ns1:0df3d864-2646-4e5d-8585-51eb154a8d23", mock.AnythingOfType("*core.OperationUpdateDTO")).Return(nil) r.ServeHTTP(res, req) assert.Equal(t, 200, res.Result().StatusCode) diff --git a/internal/apiserver/routes.go b/internal/apiserver/routes.go index 19e1738b73..7806563715 100644 --- a/internal/apiserver/routes.go +++ b/internal/apiserver/routes.go @@ -42,6 +42,12 @@ type coreExtensions struct { CoreFormUploadHandler func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) } +const ( + routeTagGlobal = "Global" + routeTagDefaultNamespace = "Default Namespace" + routeTagNonDefaultNamespace = "Non-Default Namespace" +) + var routes = append( globalRoutes([]*ffapi.Route{ getNamespace, @@ -149,7 +155,7 @@ var routes = append( func globalRoutes(routes []*ffapi.Route) []*ffapi.Route { for _, route := range routes { - route.Tag = "Global" + route.Tag = routeTagGlobal } return routes } @@ -157,7 +163,7 @@ func globalRoutes(routes []*ffapi.Route) []*ffapi.Route { func namespacedRoutes(routes []*ffapi.Route) []*ffapi.Route { newRoutes := make([]*ffapi.Route, len(routes)) for i, route := range routes { - route.Tag = "Default Namespace" + route.Tag = routeTagDefaultNamespace routeCopy := *route routeCopy.Name += "Namespace" @@ -165,7 +171,7 @@ func namespacedRoutes(routes []*ffapi.Route) []*ffapi.Route { routeCopy.PathParams = append(routeCopy.PathParams, &ffapi.PathParam{ Name: "ns", ExampleFromConf: coreconfig.NamespacesDefault, Description: coremsgs.APIParamsNamespace, }) - routeCopy.Tag = "Non-Default Namespace" + routeCopy.Tag = routeTagNonDefaultNamespace newRoutes[i] = &routeCopy } return append(routes, newRoutes...) diff --git a/internal/apiserver/server.go b/internal/apiserver/server.go index 1603aebe6d..787a73b29c 100644 --- a/internal/apiserver/server.go +++ b/internal/apiserver/server.go @@ -39,6 +39,7 @@ import ( "github.com/hyperledger/firefly/internal/events/websockets" "github.com/hyperledger/firefly/internal/metrics" "github.com/hyperledger/firefly/internal/namespace" + "github.com/hyperledger/firefly/internal/orchestrator" "github.com/hyperledger/firefly/pkg/database" ) @@ -229,8 +230,13 @@ func (as *apiServer) routeHandler(hf *ffapi.HandlerFactory, mgr namespace.Manage return nil, err } } - vars := mux.Vars(r.Req) - or := mgr.Orchestrator(extractNamespace(vars)) + + var or orchestrator.Orchestrator + if route.Tag == routeTagDefaultNamespace || route.Tag == routeTagNonDefaultNamespace { + vars := mux.Vars(r.Req) + or = mgr.Orchestrator(extractNamespace(vars)) + } + cr := &coreRequest{ mgr: mgr, or: or, @@ -242,9 +248,14 @@ func (as *apiServer) routeHandler(hf *ffapi.HandlerFactory, mgr namespace.Manage } if ce.CoreFormUploadHandler != nil { route.FormUploadHandler = func(r *ffapi.APIRequest) (output interface{}, err error) { - vars := mux.Vars(r.Req) - or := mgr.Orchestrator(extractNamespace(vars)) + var or orchestrator.Orchestrator + if route.Tag == routeTagDefaultNamespace || route.Tag == routeTagNonDefaultNamespace { + vars := mux.Vars(r.Req) + or = mgr.Orchestrator(extractNamespace(vars)) + } + cr := &coreRequest{ + mgr: mgr, or: or, ctx: r.Req.Context(), apiBaseURL: apiBaseURL, diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index 4f4f2015ab..c8e66ea709 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -62,6 +62,8 @@ type Manager interface { Orchestrator(ns string) orchestrator.Orchestrator SPIEvents() spievents.Manager GetNamespaces(ctx context.Context) ([]*core.Namespace, error) + GetOperationByNamespacedID(ctx context.Context, nsOpID string) (*core.Operation, error) + ResolveOperationByNamespacedID(ctx context.Context, nsOpID string, op *core.OperationUpdateDTO) error } type namespace struct { @@ -703,3 +705,27 @@ func (nm *namespaceManager) GetNamespaces(ctx context.Context) ([]*core.Namespac } return results, nil } + +func (nm *namespaceManager) GetOperationByNamespacedID(ctx context.Context, nsOpID string) (*core.Operation, error) { + ns, u, err := core.ParseNamespacedOpID(ctx, nsOpID) + if err != nil { + return nil, err + } + or := nm.Orchestrator(ns) + if or == nil { + return nil, i18n.NewError(ctx, coremsgs.Msg404NotFound) + } + return or.GetOperationByID(ctx, ns, u.String()) +} + +func (nm *namespaceManager) ResolveOperationByNamespacedID(ctx context.Context, nsOpID string, op *core.OperationUpdateDTO) error { + ns, u, err := core.ParseNamespacedOpID(ctx, nsOpID) + if err != nil { + return err + } + or := nm.Orchestrator(ns) + if or == nil { + return i18n.NewError(ctx, coremsgs.Msg404NotFound) + } + return or.Operations().ResolveOperationByID(ctx, ns, u, op) +} diff --git a/internal/namespace/manager_test.go b/internal/namespace/manager_test.go index 5623e0ca23..da0fd3e7f6 100644 --- a/internal/namespace/manager_test.go +++ b/internal/namespace/manager_test.go @@ -37,10 +37,12 @@ import ( "github.com/hyperledger/firefly/mocks/dataexchangemocks" "github.com/hyperledger/firefly/mocks/identitymocks" "github.com/hyperledger/firefly/mocks/metricsmocks" + "github.com/hyperledger/firefly/mocks/operationmocks" "github.com/hyperledger/firefly/mocks/orchestratormocks" "github.com/hyperledger/firefly/mocks/sharedstoragemocks" "github.com/hyperledger/firefly/mocks/spieventsmocks" "github.com/hyperledger/firefly/mocks/tokenmocks" + "github.com/hyperledger/firefly/pkg/core" "github.com/hyperledger/firefly/pkg/tokens" "github.com/spf13/viper" "github.com/stretchr/testify/assert" @@ -909,3 +911,107 @@ func TestGetNamespaces(t *testing.T) { assert.Nil(t, err) assert.Len(t, results, 1) } + +func TestGetOperationByNamespacedID(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + mo := &orchestratormocks.Orchestrator{} + nm.namespaces = map[string]*namespace{ + "default": {orchestrator: mo}, + } + + opID := fftypes.NewUUID() + mo.On("GetOperationByID", context.Background(), "default", opID.String()).Return(nil, nil) + + op, err := nm.GetOperationByNamespacedID(context.Background(), "default:"+opID.String()) + assert.Nil(t, err) + assert.Nil(t, op) + + mo.AssertExpectations(t) +} + +func TestGetOperationByNamespacedIDBadID(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + mo := &orchestratormocks.Orchestrator{} + nm.namespaces = map[string]*namespace{ + "default": {orchestrator: mo}, + } + + _, err := nm.GetOperationByNamespacedID(context.Background(), "default:bad") + assert.Regexp(t, "FF00138", err) + + mo.AssertExpectations(t) +} + +func TestGetOperationByNamespacedIDNoOrchestrator(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + mo := &orchestratormocks.Orchestrator{} + nm.namespaces = map[string]*namespace{ + "default": {orchestrator: mo}, + } + + opID := fftypes.NewUUID() + + _, err := nm.GetOperationByNamespacedID(context.Background(), "bad:"+opID.String()) + assert.Regexp(t, "FF10109", err) + + mo.AssertExpectations(t) +} + +func TestResolveOperationByNamespacedID(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + mo := &orchestratormocks.Orchestrator{} + mom := &operationmocks.Manager{} + nm.namespaces = map[string]*namespace{ + "default": {orchestrator: mo}, + } + + opID := fftypes.NewUUID() + mo.On("Operations").Return(mom) + mom.On("ResolveOperationByID", context.Background(), "default", opID, mock.Anything).Return(nil) + + err := nm.ResolveOperationByNamespacedID(context.Background(), "default:"+opID.String(), &core.OperationUpdateDTO{}) + assert.Nil(t, err) + + mo.AssertExpectations(t) + mom.AssertExpectations(t) +} + +func TestResolveOperationByNamespacedIDBadID(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + mo := &orchestratormocks.Orchestrator{} + nm.namespaces = map[string]*namespace{ + "default": {orchestrator: mo}, + } + + err := nm.ResolveOperationByNamespacedID(context.Background(), "default:bad", &core.OperationUpdateDTO{}) + assert.Regexp(t, "FF00138", err) + + mo.AssertExpectations(t) +} + +func TestResolveOperationByNamespacedIDNoOrchestrator(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + mo := &orchestratormocks.Orchestrator{} + nm.namespaces = map[string]*namespace{ + "default": {orchestrator: mo}, + } + + opID := fftypes.NewUUID() + + err := nm.ResolveOperationByNamespacedID(context.Background(), "bad:"+opID.String(), &core.OperationUpdateDTO{}) + assert.Regexp(t, "FF10109", err) + + mo.AssertExpectations(t) +} diff --git a/internal/operations/manager.go b/internal/operations/manager.go index 29b760bc9b..c5bde77b88 100644 --- a/internal/operations/manager.go +++ b/internal/operations/manager.go @@ -45,7 +45,7 @@ type Manager interface { AddOrReuseOperation(ctx context.Context, op *core.Operation) error SubmitOperationUpdate(plugin core.Named, update *OperationUpdate) TransferResult(dx dataexchange.Plugin, event dataexchange.DXEvent) - ResolveOperationByNamespacedID(ctx context.Context, nsOpID string, op *core.OperationUpdateDTO) error + ResolveOperationByID(ctx context.Context, ns string, opID *fftypes.UUID, op *core.OperationUpdateDTO) error Start() error WaitStop() } @@ -208,13 +208,8 @@ func (om *operationsManager) writeOperationFailure(ctx context.Context, ns strin } } -func (om *operationsManager) ResolveOperationByNamespacedID(ctx context.Context, nsOpID string, op *core.OperationUpdateDTO) error { - ns, u, err := core.ParseNamespacedOpID(ctx, nsOpID) - if err != nil { - return err - } - err = om.database.ResolveOperation(ctx, ns, u, op.Status, op.Error, op.Output) - return err +func (om *operationsManager) ResolveOperationByID(ctx context.Context, ns string, opID *fftypes.UUID, op *core.OperationUpdateDTO) error { + return om.database.ResolveOperation(ctx, ns, opID, op.Status, op.Error, op.Output) } func (om *operationsManager) SubmitOperationUpdate(plugin core.Named, update *OperationUpdate) { diff --git a/internal/operations/manager_test.go b/internal/operations/manager_test.go index 4adde65cc3..cf369fb7a7 100644 --- a/internal/operations/manager_test.go +++ b/internal/operations/manager_test.go @@ -565,22 +565,9 @@ func TestResolveOperationByNamespacedIDOk(t *testing.T) { "my": "data", }).Return(nil) - err := om.ResolveOperationByNamespacedID(ctx, "ns1:"+opID.String(), opUpdate) + err := om.ResolveOperationByID(ctx, "ns1", opID, opUpdate) assert.NoError(t, err) mdi.AssertExpectations(t) } - -func TestResolveOperationByNamespacedIDBadID(t *testing.T) { - om, cancel := newTestOperations(t) - defer cancel() - - ctx := context.Background() - op := &core.OperationUpdateDTO{} - - err := om.ResolveOperationByNamespacedID(ctx, "ns1:badness", op) - - assert.Regexp(t, "FF00138", err) - -} diff --git a/mocks/namespacemocks/manager.go b/mocks/namespacemocks/manager.go index 3f9981856a..32dfaaf288 100644 --- a/mocks/namespacemocks/manager.go +++ b/mocks/namespacemocks/manager.go @@ -41,6 +41,29 @@ func (_m *Manager) GetNamespaces(ctx context.Context) ([]*core.Namespace, error) return r0, r1 } +// GetOperationByNamespacedID provides a mock function with given fields: ctx, nsOpID +func (_m *Manager) GetOperationByNamespacedID(ctx context.Context, nsOpID string) (*core.Operation, error) { + ret := _m.Called(ctx, nsOpID) + + var r0 *core.Operation + if rf, ok := ret.Get(0).(func(context.Context, string) *core.Operation); ok { + r0 = rf(ctx, nsOpID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*core.Operation) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, nsOpID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Init provides a mock function with given fields: ctx, cancelCtx func (_m *Manager) Init(ctx context.Context, cancelCtx context.CancelFunc) error { ret := _m.Called(ctx, cancelCtx) @@ -71,6 +94,20 @@ func (_m *Manager) Orchestrator(ns string) orchestrator.Orchestrator { return r0 } +// ResolveOperationByNamespacedID provides a mock function with given fields: ctx, nsOpID, op +func (_m *Manager) ResolveOperationByNamespacedID(ctx context.Context, nsOpID string, op *core.OperationUpdateDTO) error { + ret := _m.Called(ctx, nsOpID, op) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, *core.OperationUpdateDTO) error); ok { + r0 = rf(ctx, nsOpID, op) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // SPIEvents provides a mock function with given fields: func (_m *Manager) SPIEvents() spievents.Manager { ret := _m.Called() diff --git a/mocks/operationmocks/manager.go b/mocks/operationmocks/manager.go index 05a37b1c89..635d59e68d 100644 --- a/mocks/operationmocks/manager.go +++ b/mocks/operationmocks/manager.go @@ -62,13 +62,13 @@ func (_m *Manager) RegisterHandler(ctx context.Context, handler operations.Opera _m.Called(ctx, handler, ops) } -// ResolveOperationByNamespacedID provides a mock function with given fields: ctx, nsOpID, op -func (_m *Manager) ResolveOperationByNamespacedID(ctx context.Context, nsOpID string, op *core.OperationUpdateDTO) error { - ret := _m.Called(ctx, nsOpID, op) +// ResolveOperationByID provides a mock function with given fields: ctx, ns, opID, op +func (_m *Manager) ResolveOperationByID(ctx context.Context, ns string, opID *fftypes.UUID, op *core.OperationUpdateDTO) error { + ret := _m.Called(ctx, ns, opID, op) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, *core.OperationUpdateDTO) error); ok { - r0 = rf(ctx, nsOpID, op) + if rf, ok := ret.Get(0).(func(context.Context, string, *fftypes.UUID, *core.OperationUpdateDTO) error); ok { + r0 = rf(ctx, ns, opID, op) } else { r0 = ret.Error(0) } From 45881b5180881376fd849f534e9b4a6e081fd57f Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Tue, 7 Jun 2022 17:00:27 -0400 Subject: [PATCH 17/33] Initialize ff_system for legacy networks Signed-off-by: Andrew Richardson --- internal/blockchain/ethereum/ethereum.go | 2 +- internal/blockchain/ethereum/ethereum_test.go | 2 +- internal/blockchain/fabric/fabric.go | 2 +- internal/blockchain/fabric/fabric_test.go | 2 +- internal/identity/identitymanager.go | 2 +- internal/identity/identitymanager_test.go | 10 +-- internal/namespace/manager.go | 88 +++++++++++-------- internal/namespace/manager_test.go | 57 ++++++++++++ mocks/blockchainmocks/plugin.go | 10 +-- pkg/blockchain/plugin.go | 2 +- 10 files changed, 126 insertions(+), 51 deletions(-) diff --git a/internal/blockchain/ethereum/ethereum.go b/internal/blockchain/ethereum/ethereum.go index 7a4627b5b0..b8cbcac7bd 100644 --- a/internal/blockchain/ethereum/ethereum.go +++ b/internal/blockchain/ethereum/ethereum.go @@ -1092,7 +1092,7 @@ func (e *Ethereum) getNetworkVersion(ctx context.Context, address string) (int, return strconv.Atoi(output.Output.(string)) } -func (e *Ethereum) NetworkVersion(ctx context.Context) int { +func (e *Ethereum) NetworkVersion() int { e.fireflyContract.mux.Lock() defer e.fireflyContract.mux.Unlock() return e.fireflyContract.networkVersion diff --git a/internal/blockchain/ethereum/ethereum_test.go b/internal/blockchain/ethereum/ethereum_test.go index 3e5d01ce41..ee0222f537 100644 --- a/internal/blockchain/ethereum/ethereum_test.go +++ b/internal/blockchain/ethereum/ethereum_test.go @@ -3004,5 +3004,5 @@ func TestHandleNetworkAction(t *testing.T) { func TestNetworkVersion(t *testing.T) { e, _ := newTestEthereum() e.fireflyContract.networkVersion = 2 - assert.Equal(t, 2, e.NetworkVersion(context.Background())) + assert.Equal(t, 2, e.NetworkVersion()) } diff --git a/internal/blockchain/fabric/fabric.go b/internal/blockchain/fabric/fabric.go index 3824c84b1e..8b4f8bed74 100644 --- a/internal/blockchain/fabric/fabric.go +++ b/internal/blockchain/fabric/fabric.go @@ -843,7 +843,7 @@ func (f *Fabric) getNetworkVersion(ctx context.Context, chaincode string) (int, return int(output.Result.(float64)), nil } -func (f *Fabric) NetworkVersion(ctx context.Context) int { +func (f *Fabric) NetworkVersion() int { f.fireflyContract.mux.Lock() defer f.fireflyContract.mux.Unlock() return f.fireflyContract.networkVersion diff --git a/internal/blockchain/fabric/fabric_test.go b/internal/blockchain/fabric/fabric_test.go index 2c08da4310..e7ecade9e3 100644 --- a/internal/blockchain/fabric/fabric_test.go +++ b/internal/blockchain/fabric/fabric_test.go @@ -2041,5 +2041,5 @@ func TestHandleNetworkAction(t *testing.T) { func TestNetworkVersion(t *testing.T) { e, _ := newTestFabric() e.fireflyContract.networkVersion = 2 - assert.Equal(t, 2, e.NetworkVersion(context.Background())) + assert.Equal(t, 2, e.NetworkVersion()) } diff --git a/internal/identity/identitymanager.go b/internal/identity/identitymanager.go index 1d4c2520a9..5408e8f33d 100644 --- a/internal/identity/identitymanager.go +++ b/internal/identity/identitymanager.go @@ -388,7 +388,7 @@ func (im *identityManager) cachedIdentityLookupByVerifierRef(ctx context.Context if err != nil { return nil, err } else if verifier == nil { - if namespace != core.LegacySystemNamespace && im.blockchain.NetworkVersion(ctx) == 1 { + if namespace != core.LegacySystemNamespace && im.blockchain.NetworkVersion() == 1 { // For V1 networks, fall back to SystemNamespace for looking up identities return im.cachedIdentityLookupByVerifierRef(ctx, core.LegacySystemNamespace, verifierRef) } diff --git a/internal/identity/identitymanager_test.go b/internal/identity/identitymanager_test.go index eb46a35b88..2b35d8c68e 100644 --- a/internal/identity/identitymanager_test.go +++ b/internal/identity/identitymanager_test.go @@ -154,7 +154,7 @@ func TestResolveInputSigningIdentityAnonymousKeyWithAuthorOk(t *testing.T) { mbi := im.blockchain.(*blockchainmocks.Plugin) mbi.On("NormalizeSigningKey", ctx, "mykey123").Return("fullkey123", nil) - mbi.On("NetworkVersion", ctx).Return(1) + mbi.On("NetworkVersion").Return(1) idID := fftypes.NewUUID() @@ -193,7 +193,7 @@ func TestResolveInputSigningIdentityKeyWithNoAuthorFail(t *testing.T) { mbi := im.blockchain.(*blockchainmocks.Plugin) mbi.On("NormalizeSigningKey", ctx, "mykey123").Return("fullkey123", nil) - mbi.On("NetworkVersion", ctx).Return(1) + mbi.On("NetworkVersion").Return(1) mdi := im.database.(*databasemocks.Plugin) mdi.On("GetVerifierByValue", ctx, core.VerifierTypeEthAddress, "ns1", "fullkey123").Return(nil, nil) @@ -259,7 +259,7 @@ func TestResolveInputSigningIdentityByKeyNotFound(t *testing.T) { mbi := im.blockchain.(*blockchainmocks.Plugin) mbi.On("NormalizeSigningKey", ctx, "mykey123").Return("fullkey123", nil) - mbi.On("NetworkVersion", ctx).Return(1) + mbi.On("NetworkVersion").Return(1) mdi := im.database.(*databasemocks.Plugin) mdi.On("GetVerifierByValue", ctx, core.VerifierTypeEthAddress, "ns1", "fullkey123"). @@ -547,7 +547,7 @@ func TestResolveDefaultSigningIdentityNotFound(t *testing.T) { } mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NetworkVersion", ctx).Return(1) + mbi.On("NetworkVersion").Return(1) mdi := im.database.(*databasemocks.Plugin) mdi.On("GetVerifierByValue", ctx, core.VerifierTypeEthAddress, "ns1", "key12345").Return(nil, nil) @@ -586,7 +586,7 @@ func TestResolveDefaultSigningIdentitySystemFallback(t *testing.T) { } mbi := im.blockchain.(*blockchainmocks.Plugin) - mbi.On("NetworkVersion", ctx).Return(1) + mbi.On("NetworkVersion").Return(1) mdi := im.database.(*databasemocks.Plugin) mdi.On("GetVerifierByValue", ctx, core.VerifierTypeEthAddress, "ns1", "key12345").Return(nil, nil) diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index c8e66ea709..abd88986cc 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -120,29 +120,50 @@ func (nm *namespaceManager) Init(ctx context.Context, cancelCtx context.CancelFu nm.ctx = ctx nm.cancelCtx = cancelCtx - err = nm.loadPlugins(ctx) - if err != nil { + if err = nm.loadPlugins(ctx); err != nil { return err } - if err = nm.loadNamespaces(ctx); err != nil { return err } + defaultNS := config.GetString(coreconfig.NamespacesDefault) + var systemNS *namespace + // Start an orchestrator per namespace for name, ns := range nm.namespaces { - or := nm.utOrchestrator - if or == nil { - or = orchestrator.NewOrchestrator(name, ns.config, ns.plugins, nm.metrics, nm.adminEvents) - } - if err = or.Init(ctx, cancelCtx); err != nil { + if err := nm.initNamespace(name, ns); err != nil { return err } - ns.orchestrator = or + + // If the default namespace is a multiparty V1 namespace, insert the legacy ff_system namespace + if name == defaultNS && ns.config.Multiparty.Enabled && ns.plugins.Blockchain.Plugin.NetworkVersion() == 1 { + systemNS = &namespace{} + *systemNS = *ns + if err := nm.initNamespace(core.LegacySystemNamespace, systemNS); err != nil { + return err + } + } + } + + if systemNS != nil { + nm.namespaces[core.LegacySystemNamespace] = systemNS } return nil } +func (nm *namespaceManager) initNamespace(name string, ns *namespace) error { + or := nm.utOrchestrator + if or == nil { + or = orchestrator.NewOrchestrator(name, ns.config, ns.plugins, nm.metrics, nm.adminEvents) + } + if err := or.Init(nm.ctx, nm.cancelCtx); err != nil { + return err + } + ns.orchestrator = or + return nil +} + func (nm *namespaceManager) Start() error { if nm.metricsEnabled { // Ensure metrics are registered @@ -486,26 +507,23 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin func (nm *namespaceManager) loadNamespaces(ctx context.Context) (err error) { defaultNS := config.GetString(coreconfig.NamespacesDefault) size := namespacePredefined.ArraySize() - namespaces := make(map[string]config.Section, size) + foundDefault := false + names := make(map[string]bool, size) for i := 0; i < size; i++ { nsConfig := namespacePredefined.ArrayEntry(i) name := nsConfig.GetString(coreconfig.NamespaceName) - if name != "" { - if _, ok := namespaces[name]; ok { - log.L(ctx).Warnf("Duplicate predefined namespace (ignored): %s", name) - } - namespaces[name] = nsConfig + if name == "" { + continue } - } - - i := 0 - foundDefault := false - for name, nsConfig := range namespaces { - if err := nm.loadNamespace(ctx, name, i, nsConfig); err != nil { - return err + if _, ok := names[name]; ok { + log.L(ctx).Warnf("Duplicate predefined namespace (ignored): %s", name) + continue } - i++ + names[name] = true foundDefault = foundDefault || name == defaultNS + if nm.namespaces[name], err = nm.loadNamespace(ctx, name, i, nsConfig); err != nil { + return err + } } if !foundDefault { return i18n.NewError(ctx, coremsgs.MsgDefaultNamespaceNotFound, defaultNS) @@ -513,13 +531,12 @@ func (nm *namespaceManager) loadNamespaces(ctx context.Context) (err error) { return err } -func (nm *namespaceManager) loadNamespace(ctx context.Context, name string, index int, conf config.Section) (err error) { +func (nm *namespaceManager) loadNamespace(ctx context.Context, name string, index int, conf config.Section) (*namespace, error) { if err := core.ValidateFFNameField(ctx, name, fmt.Sprintf("namespaces.predefined[%d].name", index)); err != nil { - return err + return nil, err } - if name == core.LegacySystemNamespace || conf.GetString(coreconfig.NamespaceRemoteName) == core.LegacySystemNamespace { - return i18n.NewError(ctx, coremsgs.MsgFFSystemReservedName, core.LegacySystemNamespace) + return nil, i18n.NewError(ctx, coremsgs.MsgFFSystemReservedName, core.LegacySystemNamespace) } // If any multiparty org information is configured (here or at the root), assume multiparty mode by default @@ -573,6 +590,7 @@ func (nm *namespaceManager) loadNamespace(ctx context.Context, name string, inde DefaultKey: conf.GetString(coreconfig.NamespaceDefaultKey), } var p *orchestrator.Plugins + var err error if multiparty.(bool) { config.Multiparty.Enabled = true config.Multiparty.OrgName = orgName @@ -582,15 +600,15 @@ func (nm *namespaceManager) loadNamespace(ctx context.Context, name string, inde } else { p, err = nm.validateGatewayConfig(ctx, name, plugins) } - - if err == nil { - nm.namespaces[name] = &namespace{ - description: conf.GetString(coreconfig.NamespaceDescription), - config: config, - plugins: *p, - } + if err != nil { + return nil, err } - return err + + return &namespace{ + description: conf.GetString(coreconfig.NamespaceDescription), + config: config, + plugins: *p, + }, nil } func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name string, plugins []string) (*orchestrator.Plugins, error) { diff --git a/internal/namespace/manager_test.go b/internal/namespace/manager_test.go index da0fd3e7f6..1c5e41834a 100644 --- a/internal/namespace/manager_test.go +++ b/internal/namespace/manager_test.go @@ -108,6 +108,9 @@ func TestInit(t *testing.T) { mo.On("Init", mock.Anything, mock.Anything).Return(nil) nm.utOrchestrator = mo + mbi := nm.plugins.blockchain["ethereum"].Plugin.(*blockchainmocks.Plugin) + mbi.On("NetworkVersion").Return(2) + ctx, cancelCtx := context.WithCancel(context.Background()) err := nm.Init(ctx, cancelCtx) assert.NoError(t, err) @@ -116,6 +119,44 @@ func TestInit(t *testing.T) { assert.Nil(t, nm.Orchestrator("unknown")) } +func TestInitVersion1(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + mo := &orchestratormocks.Orchestrator{} + mo.On("Init", mock.Anything, mock.Anything).Return(nil).Once() + mo.On("Init", mock.Anything, mock.Anything).Return(nil).Once() + nm.utOrchestrator = mo + + mbi := nm.plugins.blockchain["ethereum"].Plugin.(*blockchainmocks.Plugin) + mbi.On("NetworkVersion").Return(1) + + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.NoError(t, err) + + assert.Equal(t, mo, nm.Orchestrator("default")) + assert.Nil(t, nm.Orchestrator("unknown")) + assert.NotNil(t, nm.Orchestrator(core.LegacySystemNamespace)) +} + +func TestInitVersion1Fail(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + mo := &orchestratormocks.Orchestrator{} + mo.On("Init", mock.Anything, mock.Anything).Return(nil).Once() + mo.On("Init", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")).Once() + nm.utOrchestrator = mo + + mbi := nm.plugins.blockchain["ethereum"].Plugin.(*blockchainmocks.Plugin) + mbi.On("NetworkVersion").Return(1) + + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.EqualError(t, err, "pop") +} + func TestInitFail(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -539,6 +580,22 @@ func TestInitNamespacesDuplicate(t *testing.T) { assert.Len(t, nm.namespaces, 1) } +func TestInitNamespacesNoName(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + viper.SetConfigType("yaml") + err := viper.ReadConfig(strings.NewReader(` + namespaces: + predefined: + - plugins: [postgres] + `)) + assert.NoError(t, err) + + err = nm.loadNamespaces(context.Background()) + assert.Regexp(t, "FF10166", err) +} + func TestInitNamespacesNoDefault(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) diff --git a/mocks/blockchainmocks/plugin.go b/mocks/blockchainmocks/plugin.go index 56aa4e4e91..f59607144d 100644 --- a/mocks/blockchainmocks/plugin.go +++ b/mocks/blockchainmocks/plugin.go @@ -187,13 +187,13 @@ func (_m *Plugin) Name() string { return r0 } -// NetworkVersion provides a mock function with given fields: ctx -func (_m *Plugin) NetworkVersion(ctx context.Context) int { - ret := _m.Called(ctx) +// NetworkVersion provides a mock function with given fields: +func (_m *Plugin) NetworkVersion() int { + ret := _m.Called() var r0 int - if rf, ok := ret.Get(0).(func(context.Context) int); ok { - r0 = rf(ctx) + if rf, ok := ret.Get(0).(func() int); ok { + r0 = rf() } else { r0 = ret.Get(0).(int) } diff --git a/pkg/blockchain/plugin.go b/pkg/blockchain/plugin.go index 3445663359..1de453d529 100644 --- a/pkg/blockchain/plugin.go +++ b/pkg/blockchain/plugin.go @@ -91,7 +91,7 @@ type Plugin interface { GenerateEventSignature(ctx context.Context, event *core.FFIEventDefinition) string // NetworkVersion returns the version of the network rules being used by this plugin - NetworkVersion(ctx context.Context) int + NetworkVersion() int } const FireFlyActionPrefix = "firefly:" From e6dcaff08598c311639d2fcb1d815f80b1325eb4 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Tue, 7 Jun 2022 20:44:23 -0400 Subject: [PATCH 18/33] Factor out base PluginConfig struct Signed-off-by: Andrew Richardson --- internal/namespace/manager.go | 77 +++++++++++++++------- internal/orchestrator/orchestrator.go | 24 +++---- internal/orchestrator/orchestrator_test.go | 5 +- 3 files changed, 71 insertions(+), 35 deletions(-) diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index abd88986cc..96781b5f0b 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -256,9 +256,12 @@ func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[s } plugins[name] = orchestrator.TokensPlugin{ - Name: name, + PluginConfig: orchestrator.PluginConfig{ + Name: name, + PluginType: pluginType, + Config: config.SubSection(pluginType), + }, Plugin: plugin, - Config: config.SubSection(pluginType), } } @@ -286,9 +289,12 @@ func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[s } plugins[name] = orchestrator.TokensPlugin{ - Name: name, + PluginConfig: orchestrator.PluginConfig{ + Name: name, + PluginType: pluginType, + Config: deprecatedConfig, + }, Plugin: plugin, - Config: deprecatedConfig, } } } @@ -312,9 +318,12 @@ func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map } plugins[name] = orchestrator.DatabasePlugin{ - Name: name, + PluginConfig: orchestrator.PluginConfig{ + Name: name, + PluginType: pluginType, + Config: config.SubSection(pluginType), + }, Plugin: plugin, - Config: config.SubSection(pluginType), } } @@ -327,9 +336,12 @@ func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map } name := "database_0" plugins[name] = orchestrator.DatabasePlugin{ - Name: name, + PluginConfig: orchestrator.PluginConfig{ + Name: name, + PluginType: pluginType, + Config: deprecatedDatabaseConfig.SubSection(pluginType), + }, Plugin: plugin, - Config: deprecatedDatabaseConfig.SubSection(pluginType), } } @@ -372,9 +384,12 @@ func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins } plugins[name] = orchestrator.DataExchangePlugin{ - Name: name, + PluginConfig: orchestrator.PluginConfig{ + Name: name, + PluginType: pluginType, + Config: config.SubSection(pluginType), + }, Plugin: plugin, - Config: config.SubSection(pluginType), } } @@ -388,9 +403,12 @@ func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins name := "dataexchange_0" plugins[name] = orchestrator.DataExchangePlugin{ - Name: name, + PluginConfig: orchestrator.PluginConfig{ + Name: name, + PluginType: pluginType, + Config: deprecatedDataexchangeConfig.SubSection(pluginType), + }, Plugin: plugin, - Config: deprecatedDataexchangeConfig.SubSection(pluginType), } } @@ -413,9 +431,12 @@ func (nm *namespaceManager) getIdentityPlugins(ctx context.Context) (plugins map } plugins[name] = orchestrator.IdentityPlugin{ - Name: name, + PluginConfig: orchestrator.PluginConfig{ + Name: name, + PluginType: pluginType, + Config: config.SubSection(pluginType), + }, Plugin: plugin, - Config: config.SubSection(pluginType), } } @@ -438,9 +459,12 @@ func (nm *namespaceManager) getBlockchainPlugins(ctx context.Context) (plugins m } plugins[name] = orchestrator.BlockchainPlugin{ - Name: name, + PluginConfig: orchestrator.PluginConfig{ + Name: name, + PluginType: pluginType, + Config: config.SubSection(pluginType), + }, Plugin: plugin, - Config: config.SubSection(pluginType), } } @@ -454,9 +478,12 @@ func (nm *namespaceManager) getBlockchainPlugins(ctx context.Context) (plugins m name := "blockchain_0" plugins[name] = orchestrator.BlockchainPlugin{ - Name: name, + PluginConfig: orchestrator.PluginConfig{ + Name: name, + PluginType: pluginType, + Config: deprecatedBlockchainConfig.SubSection(pluginType), + }, Plugin: plugin, - Config: deprecatedBlockchainConfig.SubSection(pluginType), } } @@ -479,9 +506,12 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin } plugins[name] = orchestrator.SharedStoragePlugin{ - Name: name, + PluginConfig: orchestrator.PluginConfig{ + Name: name, + PluginType: pluginType, + Config: config.SubSection(pluginType), + }, Plugin: plugin, - Config: config.SubSection(pluginType), } } @@ -495,9 +525,12 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin name := "sharedstorage_0" plugins[name] = orchestrator.SharedStoragePlugin{ - Name: name, + PluginConfig: orchestrator.PluginConfig{ + Name: name, + PluginType: pluginType, + Config: deprecatedSharedStorageConfig.SubSection(pluginType), + }, Plugin: plugin, - Config: deprecatedSharedStorageConfig.SubSection(pluginType), } } diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 1b27c51f67..b5a6193449 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -119,40 +119,40 @@ type Orchestrator interface { SubmitNetworkAction(ctx context.Context, ns string, action *core.NetworkAction) error } +type PluginConfig struct { + Name string + PluginType string + Config config.Section +} + type BlockchainPlugin struct { - Name string + PluginConfig Plugin blockchain.Plugin - Config config.Section } type DatabasePlugin struct { - Name string + PluginConfig Plugin database.Plugin - Config config.Section } type DataExchangePlugin struct { - Name string + PluginConfig Plugin dataexchange.Plugin - Config config.Section } type SharedStoragePlugin struct { - Name string + PluginConfig Plugin sharedstorage.Plugin - Config config.Section } type TokensPlugin struct { - Name string + PluginConfig Plugin tokens.Plugin - Config config.Section } type IdentityPlugin struct { - Name string + PluginConfig Plugin idplugin.Plugin - Config config.Section } type Plugins struct { diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index 0665c0d0d6..9e2fdf1268 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -156,7 +156,10 @@ func newTestOrchestrator() *testOrchestrator { tor.orchestrator.plugins.SharedStorage.Plugin = tor.mps tor.orchestrator.plugins.DataExchange.Plugin = tor.mdx tor.orchestrator.plugins.Database.Plugin = tor.mdi - tor.orchestrator.plugins.Tokens = []TokensPlugin{{Name: "token", Plugin: tor.mti}} + tor.orchestrator.plugins.Tokens = []TokensPlugin{{ + PluginConfig: PluginConfig{Name: "token"}, + Plugin: tor.mti, + }} tor.mdi.On("Name").Return("mock-di").Maybe() tor.mem.On("Name").Return("mock-ei").Maybe() tor.mps.On("Name").Return("mock-ps").Maybe() From 161b6ef178a4dfe98c53830ac039c61b1439fe59 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Tue, 7 Jun 2022 21:54:27 -0400 Subject: [PATCH 19/33] Split out plugin RegisterListener from Init Signed-off-by: Andrew Richardson --- internal/blockchain/ethereum/ethereum.go | 7 ++- internal/blockchain/ethereum/ethereum_test.go | 48 +++++++-------- internal/blockchain/fabric/fabric.go | 7 ++- internal/blockchain/fabric/fabric_test.go | 36 +++++------ internal/database/postgres/postgres.go | 8 ++- internal/database/postgres/postgres_test.go | 4 +- .../database/sqlcommon/provider_mock_test.go | 3 +- .../sqlcommon/provider_sqlitego_test.go | 3 +- internal/database/sqlcommon/sqlcommon.go | 7 ++- internal/database/sqlcommon/sqlcommon_test.go | 8 +-- internal/database/sqlite3/sqlite3.go | 8 ++- internal/database/sqlite3/sqlite3_test.go | 4 +- internal/dataexchange/ffdx/ffdx.go | 7 ++- internal/dataexchange/ffdx/ffdx_test.go | 14 +++-- internal/identity/tbd/tbd.go | 7 ++- internal/identity/tbd/tbd_test.go | 3 +- internal/orchestrator/orchestrator.go | 21 ++++--- internal/orchestrator/orchestrator_test.go | 61 ++++++++++++------- internal/sharedstorage/ipfs/ipfs.go | 7 ++- internal/sharedstorage/ipfs/ipfs_test.go | 17 +++--- internal/tokens/fftokens/fftokens.go | 7 ++- internal/tokens/fftokens/fftokens_test.go | 18 +++--- mocks/blockchainmocks/plugin.go | 15 +++-- mocks/databasemocks/plugin.go | 15 +++-- mocks/dataexchangemocks/plugin.go | 15 +++-- mocks/identitymocks/plugin.go | 15 +++-- mocks/sharedstoragemocks/plugin.go | 15 +++-- mocks/tokenmocks/plugin.go | 15 +++-- pkg/blockchain/plugin.go | 5 +- pkg/database/plugin.go | 6 +- pkg/dataexchange/plugin.go | 5 +- pkg/identity/plugin.go | 6 +- pkg/sharedstorage/plugin.go | 6 +- pkg/tokens/plugin.go | 6 +- 34 files changed, 262 insertions(+), 167 deletions(-) diff --git a/internal/blockchain/ethereum/ethereum.go b/internal/blockchain/ethereum/ethereum.go index b8cbcac7bd..340ace0d83 100644 --- a/internal/blockchain/ethereum/ethereum.go +++ b/internal/blockchain/ethereum/ethereum.go @@ -156,14 +156,13 @@ func (e *Ethereum) VerifierType() core.VerifierType { return core.VerifierTypeEthAddress } -func (e *Ethereum) Init(ctx context.Context, config config.Section, callbacks blockchain.Callbacks, metrics metrics.Manager) (err error) { +func (e *Ethereum) Init(ctx context.Context, config config.Section, metrics metrics.Manager) (err error) { e.InitConfig(config) ethconnectConf := e.ethconnectConf addressResolverConf := config.SubSection(AddressResolverConfigKey) fftmConf := config.SubSection(FFTMConfigKey) e.ctx = log.WithLogField(ctx, "proto", "ethereum") - e.callbacks = callbacks e.metrics = metrics e.capabilities = &blockchain.Capabilities{} @@ -214,6 +213,10 @@ func (e *Ethereum) Init(ctx context.Context, config config.Section, callbacks bl return nil } +func (e *Ethereum) RegisterListener(callbacks blockchain.Callbacks) { + e.callbacks = callbacks +} + func (e *Ethereum) Start() (err error) { return e.wsconn.Connect() } diff --git a/internal/blockchain/ethereum/ethereum_test.go b/internal/blockchain/ethereum/ethereum_test.go index ee0222f537..0a1a06c60b 100644 --- a/internal/blockchain/ethereum/ethereum_test.go +++ b/internal/blockchain/ethereum/ethereum_test.go @@ -120,7 +120,7 @@ func TestInitMissingURL(t *testing.T) { e, cancel := newTestEthereum() defer cancel() resetConf(e) - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.Regexp(t, "FF10138.*url", err) } @@ -129,7 +129,7 @@ func TestInitBadAddressResolver(t *testing.T) { defer cancel() resetConf(e) utAddressResolverConf.Set(AddressResolverURLTemplate, "{{unclosed}") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.Regexp(t, "FF10337.*urlTemplate", err) } @@ -140,7 +140,7 @@ func TestInitMissingTopic(t *testing.T) { utEthconnectConf.Set(ffresty.HTTPConfigURL, "http://localhost:12345") utEthconnectConf.Set(EthconnectConfigInstanceDeprecated, "/instances/0x12345") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.Regexp(t, "FF10138.*topic", err) } @@ -183,7 +183,7 @@ func TestInitAndStartWithFFTM(t *testing.T) { utEthconnectConf.Set(EthconnectConfigTopic, "topic1") utFFTMConf.Set(ffresty.HTTPConfigURL, "http://fftm.example.com:12345") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) assert.NotNil(t, e.fftmClient) @@ -226,7 +226,7 @@ func TestWSInitFail(t *testing.T) { utEthconnectConf.Set(EthconnectConfigInstanceDeprecated, "/instances/0x71C7656EC7ab88b098defB751B7401B5f6d8976F") utEthconnectConf.Set(EthconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.Regexp(t, "FF00149", err) } @@ -250,7 +250,7 @@ func TestInitMissingInstance(t *testing.T) { utEthconnectConf.Set(ffresty.HTTPCustomClient, mockedClient) utEthconnectConf.Set(EthconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "FF10138.*instance", err) @@ -282,7 +282,7 @@ func TestInitAllExistingStreams(t *testing.T) { utEthconnectConf.Set(EthconnectConfigInstanceDeprecated, "0x71C7656EC7ab88b098defB751B7401B5f6d8976F") utEthconnectConf.Set(EthconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.NoError(t, err) @@ -333,7 +333,7 @@ func TestInitOldInstancePathContracts(t *testing.T) { utEthconnectConf.Set(EthconnectConfigInstanceDeprecated, "/contracts/firefly") utEthconnectConf.Set(EthconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.NoError(t, err) @@ -371,7 +371,7 @@ func TestInitOldInstancePathInstances(t *testing.T) { utEthconnectConf.Set(EthconnectConfigInstanceDeprecated, "/instances/0x71C7656EC7ab88b098defB751B7401B5f6d8976F") utEthconnectConf.Set(EthconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.NoError(t, err) @@ -411,7 +411,7 @@ func TestInitOldInstancePathError(t *testing.T) { utEthconnectConf.Set(EthconnectConfigInstanceDeprecated, "/contracts/firefly") utEthconnectConf.Set(EthconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "FF10111.*pop", err) @@ -442,7 +442,7 @@ func TestInitNewConfig(t *testing.T) { utEthconnectConf.Set(EthconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractAddress, "0x71C7656EC7ab88b098defB751B7401B5f6d8976F") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.NoError(t, err) @@ -471,7 +471,7 @@ func TestInitNewConfigError(t *testing.T) { utEthconnectConf.Set(EthconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractAddress, "") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "FF10138", err) @@ -497,7 +497,7 @@ func TestInitNewConfigBadIndex(t *testing.T) { utEthconnectConf.Set(EthconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractAddress, "") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{ Active: core.FireFlyContractInfo{Index: 1}, @@ -531,7 +531,7 @@ func TestInitNetworkVersionNotFound(t *testing.T) { utEthconnectConf.Set(EthconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractAddress, "0x71C7656EC7ab88b098defB751B7401B5f6d8976F") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.NoError(t, err) @@ -566,7 +566,7 @@ func TestInitNetworkVersionError(t *testing.T) { utEthconnectConf.Set(EthconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractAddress, "0x71C7656EC7ab88b098defB751B7401B5f6d8976F") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "FF10111", err) @@ -598,7 +598,7 @@ func TestInitNetworkVersionBadResponse(t *testing.T) { utEthconnectConf.Set(EthconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractAddress, "0x71C7656EC7ab88b098defB751B7401B5f6d8976F") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "json: cannot unmarshal", err) @@ -636,7 +636,7 @@ func TestInitTerminateContract(t *testing.T) { utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractAddress, "0x1C197604587F046FD40684A8f21f4609FB811A7b") utConfig.AddKnownKey(FireFlyContractConfigKey+".1."+FireFlyContractAddress, "0x71C7656EC7ab88b098defB751B7401B5f6d8976F") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, contracts) assert.NoError(t, err) @@ -694,7 +694,7 @@ func TestInitTerminateContractIgnore(t *testing.T) { utEthconnectConf.Set(EthconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractAddress, "0x71C7656EC7ab88b098defB751B7401B5f6d8976F") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, contracts) assert.NoError(t, err) @@ -734,7 +734,7 @@ func TestInitTerminateContractBadEvent(t *testing.T) { utEthconnectConf.Set(EthconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractAddress, "0x71C7656EC7ab88b098defB751B7401B5f6d8976F") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, contracts) assert.NoError(t, err) @@ -762,7 +762,7 @@ func TestStreamQueryError(t *testing.T) { utEthconnectConf.Set(EthconnectConfigInstanceDeprecated, "/instances/0x71C7656EC7ab88b098defB751B7401B5f6d8976F") utEthconnectConf.Set(EthconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.Regexp(t, "FF10111.*pop", err) } @@ -788,7 +788,7 @@ func TestStreamCreateError(t *testing.T) { utEthconnectConf.Set(EthconnectConfigInstanceDeprecated, "/instances/0x71C7656EC7ab88b098defB751B7401B5f6d8976F") utEthconnectConf.Set(EthconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.Regexp(t, "FF10111.*pop", err) } @@ -814,7 +814,7 @@ func TestStreamUpdateError(t *testing.T) { utEthconnectConf.Set(EthconnectConfigInstanceDeprecated, "/instances/0x71C7656EC7ab88b098defB751B7401B5f6d8976F") utEthconnectConf.Set(EthconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.Regexp(t, "FF10111.*pop", err) } @@ -842,7 +842,7 @@ func TestSubQueryError(t *testing.T) { utEthconnectConf.Set(EthconnectConfigInstanceDeprecated, "/instances/0x71C7656EC7ab88b098defB751B7401B5f6d8976F") utEthconnectConf.Set(EthconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "FF10111.*pop", err) @@ -874,7 +874,7 @@ func TestSubQueryCreateError(t *testing.T) { utEthconnectConf.Set(EthconnectConfigInstanceDeprecated, "/instances/0x71C7656EC7ab88b098defB751B7401B5f6d8976F") utEthconnectConf.Set(EthconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "FF10111.*pop", err) diff --git a/internal/blockchain/fabric/fabric.go b/internal/blockchain/fabric/fabric.go index 8b4f8bed74..33547deecb 100644 --- a/internal/blockchain/fabric/fabric.go +++ b/internal/blockchain/fabric/fabric.go @@ -161,12 +161,11 @@ func (f *Fabric) VerifierType() core.VerifierType { return core.VerifierTypeMSPIdentity } -func (f *Fabric) Init(ctx context.Context, config config.Section, callbacks blockchain.Callbacks, metrics metrics.Manager) (err error) { +func (f *Fabric) Init(ctx context.Context, config config.Section, metrics metrics.Manager) (err error) { f.InitConfig(config) fabconnectConf := f.fabconnectConf f.ctx = log.WithLogField(ctx, "proto", "fabric") - f.callbacks = callbacks f.idCache = make(map[string]*fabIdentity) f.metrics = metrics f.capabilities = &blockchain.Capabilities{} @@ -286,6 +285,10 @@ func (f *Fabric) TerminateContract(ctx context.Context, contracts *core.FireFlyC return f.ConfigureContract(ctx, contracts) } +func (f *Fabric) RegisterListener(callbacks blockchain.Callbacks) { + f.callbacks = callbacks +} + func (f *Fabric) Start() (err error) { return f.wsconn.Connect() } diff --git a/internal/blockchain/fabric/fabric_test.go b/internal/blockchain/fabric/fabric_test.go index e7ecade9e3..4cb08d01a0 100644 --- a/internal/blockchain/fabric/fabric_test.go +++ b/internal/blockchain/fabric/fabric_test.go @@ -118,7 +118,7 @@ func TestInitMissingURL(t *testing.T) { e, cancel := newTestFabric() defer cancel() resetConf(e) - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.Regexp(t, "FF10138.*url", err) } @@ -130,7 +130,7 @@ func TestInitMissingTopic(t *testing.T) { utFabconnectConf.Set(FabconnectConfigChaincodeDeprecated, "Firefly") utFabconnectConf.Set(FabconnectConfigSigner, "signer001") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.Regexp(t, "FF10138.*topic", err) } @@ -174,7 +174,7 @@ func TestInitAllNewStreamsAndWSEvent(t *testing.T) { utFabconnectConf.Set(FabconnectConfigSigner, "signer001") utFabconnectConf.Set(FabconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.NoError(t, err) assert.Equal(t, "fabric", e.Name()) @@ -216,7 +216,7 @@ func TestWSInitFail(t *testing.T) { utFabconnectConf.Set(FabconnectConfigSigner, "signer001") utFabconnectConf.Set(FabconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.Regexp(t, "FF00149", err) } @@ -240,7 +240,7 @@ func TestInitMissingInstance(t *testing.T) { utFabconnectConf.Set(ffresty.HTTPCustomClient, mockedClient) utFabconnectConf.Set(FabconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "FF10138.*chaincode", err) @@ -271,7 +271,7 @@ func TestInitAllExistingStreams(t *testing.T) { utFabconnectConf.Set(FabconnectConfigSigner, "signer001") utFabconnectConf.Set(FabconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.NoError(t, err) @@ -307,7 +307,7 @@ func TestInitNewConfig(t *testing.T) { utFabconnectConf.Set(FabconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractChaincode, "firefly") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.NoError(t, err) @@ -337,7 +337,7 @@ func TestInitNewConfigError(t *testing.T) { utFabconnectConf.Set(FabconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractChaincode, "") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "FF10138", err) @@ -363,7 +363,7 @@ func TestInitNewConfigBadIndex(t *testing.T) { utFabconnectConf.Set(FabconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractChaincode, "") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{ Active: core.FireFlyContractInfo{Index: 1}, @@ -399,7 +399,7 @@ func TestInitNetworkVersionNotFound(t *testing.T) { utFabconnectConf.Set(FabconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractChaincode, "firefly") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.NoError(t, err) @@ -435,7 +435,7 @@ func TestInitNetworkVersionError(t *testing.T) { utFabconnectConf.Set(FabconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractChaincode, "firefly") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "FF10284", err) @@ -468,7 +468,7 @@ func TestInitNetworkVersionBadResponse(t *testing.T) { utFabconnectConf.Set(FabconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractChaincode, "firefly") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, e.metrics) + err := e.Init(e.ctx, utConfig, e.metrics) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "json: cannot unmarshal", err) @@ -507,7 +507,7 @@ func TestInitTerminateContract(t *testing.T) { utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractChaincode, "firefly") utConfig.AddKnownKey(FireFlyContractConfigKey+".1."+FireFlyContractChaincode, "firefly2") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, contracts) assert.NoError(t, err) @@ -566,7 +566,7 @@ func TestInitTerminateContractIgnore(t *testing.T) { utFabconnectConf.Set(FabconnectConfigTopic, "topic1") utConfig.AddKnownKey(FireFlyContractConfigKey+".0."+FireFlyContractChaincode, "firefly") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, contracts) assert.NoError(t, err) @@ -603,7 +603,7 @@ func TestStreamQueryError(t *testing.T) { utFabconnectConf.Set(FabconnectConfigSigner, "signer001") utFabconnectConf.Set(FabconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.Regexp(t, "FF10284.*pop", err) } @@ -630,7 +630,7 @@ func TestStreamCreateError(t *testing.T) { utFabconnectConf.Set(FabconnectConfigSigner, "signer001") utFabconnectConf.Set(FabconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.Regexp(t, "FF10284.*pop", err) } @@ -659,7 +659,7 @@ func TestSubQueryError(t *testing.T) { utFabconnectConf.Set(FabconnectConfigSigner, "signer001") utFabconnectConf.Set(FabconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "FF10284.*pop", err) @@ -692,7 +692,7 @@ func TestSubQueryCreateError(t *testing.T) { utFabconnectConf.Set(FabconnectConfigSigner, "signer001") utFabconnectConf.Set(FabconnectConfigTopic, "topic1") - err := e.Init(e.ctx, utConfig, &blockchainmocks.Callbacks{}, &metricsmocks.Manager{}) + err := e.Init(e.ctx, utConfig, &metricsmocks.Manager{}) assert.NoError(t, err) err = e.ConfigureContract(e.ctx, &core.FireFlyContracts{}) assert.Regexp(t, "FF10284.*pop", err) diff --git a/internal/database/postgres/postgres.go b/internal/database/postgres/postgres.go index cda5c18bc4..90d5b067e1 100644 --- a/internal/database/postgres/postgres.go +++ b/internal/database/postgres/postgres.go @@ -37,9 +37,13 @@ type Postgres struct { sqlcommon.SQLCommon } -func (psql *Postgres) Init(ctx context.Context, config config.Section, callbacks database.Callbacks) error { +func (psql *Postgres) Init(ctx context.Context, config config.Section) error { capabilities := &database.Capabilities{} - return psql.SQLCommon.Init(ctx, psql, config, callbacks, capabilities) + return psql.SQLCommon.Init(ctx, psql, config, capabilities) +} + +func (psql *Postgres) RegisterListener(callbacks database.Callbacks) { + psql.SQLCommon.RegisterListener(callbacks) } func (psql *Postgres) Name() string { diff --git a/internal/database/postgres/postgres_test.go b/internal/database/postgres/postgres_test.go index 1dd8d2f149..b1a41a8143 100644 --- a/internal/database/postgres/postgres_test.go +++ b/internal/database/postgres/postgres_test.go @@ -23,17 +23,15 @@ import ( sq "github.com/Masterminds/squirrel" "github.com/hyperledger/firefly-common/pkg/config" "github.com/hyperledger/firefly/internal/database/sqlcommon" - "github.com/hyperledger/firefly/mocks/databasemocks" "github.com/stretchr/testify/assert" ) func TestPostgresProvider(t *testing.T) { psql := &Postgres{} - dcb := &databasemocks.Callbacks{} config := config.RootSection("unittest") psql.InitConfig(config) config.Set(sqlcommon.SQLConfDatasourceURL, "!bad connection") - err := psql.Init(context.Background(), config, dcb) + err := psql.Init(context.Background(), config) assert.NoError(t, err) _, err = psql.GetMigrationDriver(psql.DB()) assert.Error(t, err) diff --git a/internal/database/sqlcommon/provider_mock_test.go b/internal/database/sqlcommon/provider_mock_test.go index 166a4f841f..9671c1a05b 100644 --- a/internal/database/sqlcommon/provider_mock_test.go +++ b/internal/database/sqlcommon/provider_mock_test.go @@ -63,7 +63,8 @@ func newMockProvider() *mockProvider { // init is a convenience to init for tests that aren't testing init itself func (mp *mockProvider) init() (*mockProvider, sqlmock.Sqlmock) { - _ = mp.Init(context.Background(), mp, mp.config, mp.callbacks, mp.capabilities) + _ = mp.Init(context.Background(), mp, mp.config, mp.capabilities) + mp.RegisterListener(mp.callbacks) return mp, mp.mdb } diff --git a/internal/database/sqlcommon/provider_sqlitego_test.go b/internal/database/sqlcommon/provider_sqlitego_test.go index 8e2815c6d9..be0ea34939 100644 --- a/internal/database/sqlcommon/provider_sqlitego_test.go +++ b/internal/database/sqlcommon/provider_sqlitego_test.go @@ -63,8 +63,9 @@ func newSQLiteTestProvider(t *testing.T) (*sqliteGoTestProvider, func()) { tp.config.Set(SQLConfMigrationsDirectory, "../../../db/migrations/sqlite") tp.config.Set(SQLConfMaxConnections, 1) - err = tp.Init(context.Background(), tp, tp.config, tp.callbacks, tp.capabilities) + err = tp.Init(context.Background(), tp, tp.config, tp.capabilities) assert.NoError(tp.t, err) + tp.RegisterListener(tp.callbacks) return tp, func() { tp.Close() diff --git a/internal/database/sqlcommon/sqlcommon.go b/internal/database/sqlcommon/sqlcommon.go index 884b00bb29..fc5d45b0ee 100644 --- a/internal/database/sqlcommon/sqlcommon.go +++ b/internal/database/sqlcommon/sqlcommon.go @@ -53,9 +53,8 @@ type txWrapper struct { tableLocks []string } -func (s *SQLCommon) Init(ctx context.Context, provider Provider, config config.Section, callbacks database.Callbacks, capabilities *database.Capabilities) (err error) { +func (s *SQLCommon) Init(ctx context.Context, provider Provider, config config.Section, capabilities *database.Capabilities) (err error) { s.capabilities = capabilities - s.callbacks = callbacks s.provider = provider if s.provider != nil { s.features = s.provider.Features() @@ -97,6 +96,10 @@ func (s *SQLCommon) Init(ctx context.Context, provider Provider, config config.S return nil } +func (s *SQLCommon) RegisterListener(callbacks database.Callbacks) { + s.callbacks = callbacks +} + func (s *SQLCommon) Capabilities() *database.Capabilities { return s.capabilities } func (s *SQLCommon) RunAsGroup(ctx context.Context, fn func(ctx context.Context) error) error { diff --git a/internal/database/sqlcommon/sqlcommon_test.go b/internal/database/sqlcommon/sqlcommon_test.go index ee76f59246..27f3b0c54e 100644 --- a/internal/database/sqlcommon/sqlcommon_test.go +++ b/internal/database/sqlcommon/sqlcommon_test.go @@ -42,7 +42,7 @@ func TestInitSQLCommonMissingURL(t *testing.T) { config: conf, } s.InitConfig(tp, conf) - err := s.Init(context.Background(), tp, conf, nil, nil) + err := s.Init(context.Background(), tp, conf, nil) assert.Regexp(t, "FF10138.*url", err) } @@ -55,14 +55,14 @@ func TestInitSQLCommon(t *testing.T) { func TestInitSQLCommonMissingOptions(t *testing.T) { s := &SQLCommon{} - err := s.Init(context.Background(), nil, nil, nil, nil) + err := s.Init(context.Background(), nil, nil, nil) assert.Regexp(t, "FF10112", err) } func TestInitSQLCommonOpenFailed(t *testing.T) { mp := newMockProvider() mp.openError = fmt.Errorf("pop") - err := mp.SQLCommon.Init(context.Background(), mp, mp.config, mp.callbacks, mp.capabilities) + err := mp.SQLCommon.Init(context.Background(), mp, mp.config, mp.capabilities) assert.Regexp(t, "FF10112.*pop", err) } @@ -70,7 +70,7 @@ func TestInitSQLCommonMigrationOpenFailed(t *testing.T) { mp := newMockProvider() mp.config.Set(SQLConfMigrationsAuto, true) mp.getMigrationDriverError = fmt.Errorf("pop") - err := mp.SQLCommon.Init(context.Background(), mp, mp.config, mp.callbacks, mp.capabilities) + err := mp.SQLCommon.Init(context.Background(), mp, mp.config, mp.capabilities) assert.Regexp(t, "FF10163.*pop", err) } diff --git a/internal/database/sqlite3/sqlite3.go b/internal/database/sqlite3/sqlite3.go index 6232063be2..73879dd755 100644 --- a/internal/database/sqlite3/sqlite3.go +++ b/internal/database/sqlite3/sqlite3.go @@ -46,7 +46,7 @@ func connHook(conn *sqlite3.SQLiteConn) error { return err } -func (sqlite *SQLite3) Init(ctx context.Context, config config.Section, callbacks database.Callbacks) error { +func (sqlite *SQLite3) Init(ctx context.Context, config config.Section) error { capabilities := &database.Capabilities{} if !ffSQLiteRegistered { sql.Register("sqlite3_ff", @@ -55,7 +55,11 @@ func (sqlite *SQLite3) Init(ctx context.Context, config config.Section, callback }) ffSQLiteRegistered = true } - return sqlite.SQLCommon.Init(ctx, sqlite, config, callbacks, capabilities) + return sqlite.SQLCommon.Init(ctx, sqlite, config, capabilities) +} + +func (sqlite *SQLite3) RegisterListener(callbacks database.Callbacks) { + sqlite.SQLCommon.RegisterListener(callbacks) } func (sqlite *SQLite3) Name() string { diff --git a/internal/database/sqlite3/sqlite3_test.go b/internal/database/sqlite3/sqlite3_test.go index fc4ef26890..8c4cdc5716 100644 --- a/internal/database/sqlite3/sqlite3_test.go +++ b/internal/database/sqlite3/sqlite3_test.go @@ -26,17 +26,15 @@ import ( sq "github.com/Masterminds/squirrel" "github.com/hyperledger/firefly-common/pkg/config" "github.com/hyperledger/firefly/internal/database/sqlcommon" - "github.com/hyperledger/firefly/mocks/databasemocks" "github.com/stretchr/testify/assert" ) func TestSQLite3GoProvider(t *testing.T) { sqlite := &SQLite3{} - dcb := &databasemocks.Callbacks{} config := config.RootSection("unittest") sqlite.InitConfig(config) config.Set(sqlcommon.SQLConfDatasourceURL, "!wrong://") - err := sqlite.Init(context.Background(), config, dcb) + err := sqlite.Init(context.Background(), config) assert.NoError(t, err) _, err = sqlite.GetMigrationDriver(sqlite.DB()) assert.Error(t, err) diff --git a/internal/dataexchange/ffdx/ffdx.go b/internal/dataexchange/ffdx/ffdx.go index 59fd902e50..8f3924a368 100644 --- a/internal/dataexchange/ffdx/ffdx.go +++ b/internal/dataexchange/ffdx/ffdx.go @@ -108,9 +108,8 @@ func (h *FFDX) Name() string { return "ffdx" } -func (h *FFDX) Init(ctx context.Context, config config.Section, nodes []fftypes.JSONObject, callbacks dataexchange.Callbacks) (err error) { +func (h *FFDX) Init(ctx context.Context, config config.Section, nodes []fftypes.JSONObject) (err error) { h.ctx = log.WithLogField(ctx, "dx", "https") - h.callbacks = callbacks h.ackChannel = make(chan *ack) h.needsInit = config.GetBool(DataExchangeInitEnabled) @@ -137,6 +136,10 @@ func (h *FFDX) Init(ctx context.Context, config config.Section, nodes []fftypes. return nil } +func (h *FFDX) RegisterListener(callbacks dataexchange.Callbacks) { + h.callbacks = callbacks +} + func (h *FFDX) Start() error { return h.wsconn.Connect() } diff --git a/internal/dataexchange/ffdx/ffdx_test.go b/internal/dataexchange/ffdx/ffdx_test.go index dca671ad93..2dfdb294c0 100644 --- a/internal/dataexchange/ffdx/ffdx_test.go +++ b/internal/dataexchange/ffdx/ffdx_test.go @@ -63,7 +63,7 @@ func newTestFFDX(t *testing.T, manifestEnabled bool) (h *FFDX, toServer, fromSer h.InitConfig(utConfig) dxCtx, dxCancel := context.WithCancel(context.Background()) - err := h.Init(dxCtx, utConfig, nodes, &dataexchangemocks.Callbacks{}) + err := h.Init(dxCtx, utConfig, nodes) assert.NoError(t, err) assert.Equal(t, "ffdx", h.Name()) assert.NotNil(t, h.Capabilities()) @@ -80,7 +80,7 @@ func TestInitBadURL(t *testing.T) { nodes := make([]fftypes.JSONObject, 0) h.InitConfig(utConfig) utConfig.Set(ffresty.HTTPConfigURL, "::::////") - err := h.Init(context.Background(), utConfig, nodes, &dataexchangemocks.Callbacks{}) + err := h.Init(context.Background(), utConfig, nodes) assert.Regexp(t, "FF00149", err) } @@ -89,7 +89,7 @@ func TestInitMissingURL(t *testing.T) { h := &FFDX{} nodes := make([]fftypes.JSONObject, 0) h.InitConfig(utConfig) - err := h.Init(context.Background(), utConfig, nodes, &dataexchangemocks.Callbacks{}) + err := h.Init(context.Background(), utConfig, nodes) assert.Regexp(t, "FF10138", err) } @@ -445,7 +445,8 @@ func TestEvents(t *testing.T) { msg := <-toServer assert.Equal(t, `{"action":"ack","id":"0"}`, string(msg)) - mcb := h.callbacks.(*dataexchangemocks.Callbacks) + mcb := &dataexchangemocks.Callbacks{} + h.callbacks = mcb mcb.On("DXEvent", mock.MatchedBy(func(ev dataexchange.DXEvent) bool { return ev.NamespacedID() == "1" && @@ -558,7 +559,8 @@ func TestEventsWithManifest(t *testing.T) { msg := <-toServer assert.Equal(t, `{"action":"ack","id":"0"}`, string(msg)) - mcb := h.callbacks.(*dataexchangemocks.Callbacks) + mcb := &dataexchangemocks.Callbacks{} + h.callbacks = mcb mcb.On("DXEvent", mock.MatchedBy(func(ev dataexchange.DXEvent) bool { return ev.NamespacedID() == "1" && @@ -679,7 +681,7 @@ func TestWebsocketWithReinit(t *testing.T) { }) h.InitConfig(utConfig) - err := h.Init(context.Background(), utConfig, nodes, &dataexchangemocks.Callbacks{}) + err := h.Init(context.Background(), utConfig, nodes) assert.NoError(t, err) err = h.Start() diff --git a/internal/identity/tbd/tbd.go b/internal/identity/tbd/tbd.go index a99801e25e..507d8aedf0 100644 --- a/internal/identity/tbd/tbd.go +++ b/internal/identity/tbd/tbd.go @@ -33,12 +33,15 @@ func (tbd *TBD) Name() string { return "onchain" // For backwards compatibility with previous config that might have specified "onchain" } -func (tbd *TBD) Init(ctx context.Context, config config.Section, callbacks identity.Callbacks) (err error) { - tbd.callbacks = callbacks +func (tbd *TBD) Init(ctx context.Context, config config.Section) (err error) { tbd.capabilities = &identity.Capabilities{} return nil } +func (tbd *TBD) RegisterListener(callbacks identity.Callbacks) { + tbd.callbacks = callbacks +} + func (tbd *TBD) Start() error { return nil } diff --git a/internal/identity/tbd/tbd_test.go b/internal/identity/tbd/tbd_test.go index 5a555fb6d9..5eb97611df 100644 --- a/internal/identity/tbd/tbd_test.go +++ b/internal/identity/tbd/tbd_test.go @@ -21,7 +21,6 @@ import ( "testing" "github.com/hyperledger/firefly-common/pkg/config" - "github.com/hyperledger/firefly/mocks/identitymocks" "github.com/hyperledger/firefly/pkg/identity" "github.com/stretchr/testify/assert" ) @@ -31,7 +30,7 @@ var utConfig = config.RootSection("onchain_unit_tests") func TestInit(t *testing.T) { var oc identity.Plugin = &TBD{} oc.InitConfig(utConfig) - err := oc.Init(context.Background(), utConfig, &identitymocks.Callbacks{}) + err := oc.Init(context.Background(), utConfig) assert.NoError(t, err) assert.Equal(t, "onchain", oc.Name()) err = oc.Start() diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index b5a6193449..c7f6e0f5d7 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -367,15 +367,15 @@ func (or *orchestrator) Operations() operations.Manager { } func (or *orchestrator) initPlugins(ctx context.Context) (err error) { - err = or.plugins.Database.Plugin.Init(ctx, or.plugins.Database.Config, or) - if err != nil { + if err = or.plugins.Database.Plugin.Init(ctx, or.plugins.Database.Config); err != nil { return err } + or.plugins.Database.Plugin.RegisterListener(or) - err = or.plugins.Blockchain.Plugin.Init(ctx, or.plugins.Blockchain.Config, &or.bc, or.metrics) - if err != nil { + if err = or.plugins.Blockchain.Plugin.Init(ctx, or.plugins.Blockchain.Config, or.metrics); err != nil { return err } + or.plugins.Blockchain.Plugin.RegisterListener(&or.bc) fb := database.IdentityQueryFactory.NewFilter(ctx) nodes, _, err := or.database().GetIdentities(ctx, fb.And( @@ -389,18 +389,21 @@ func (or *orchestrator) initPlugins(ctx context.Context) (err error) { nodeInfo[i] = node.Profile } - err = or.plugins.DataExchange.Plugin.Init(ctx, or.plugins.DataExchange.Config, nodeInfo, &or.bc) - if err != nil { + if err = or.plugins.DataExchange.Plugin.Init(ctx, or.plugins.DataExchange.Config, nodeInfo); err != nil { return err } + or.plugins.DataExchange.Plugin.RegisterListener(&or.bc) - err = or.plugins.SharedStorage.Plugin.Init(ctx, or.plugins.SharedStorage.Config, &or.bc) - if err != nil { + if err = or.plugins.SharedStorage.Plugin.Init(ctx, or.plugins.SharedStorage.Config); err != nil { return err } + or.plugins.SharedStorage.Plugin.RegisterListener(&or.bc) for _, token := range or.plugins.Tokens { - err = token.Plugin.Init(ctx, token.Name, token.Config, &or.bc) + if err = token.Plugin.Init(ctx, token.Name, token.Config); err != nil { + return err + } + token.Plugin.RegisterListener(&or.bc) } return err diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index 9e2fdf1268..32fd67b676 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -187,7 +187,7 @@ func TestNewOrchestrator(t *testing.T) { func TestInitPluginsDatabaseFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + or.mdi.On("Init", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) ctx := context.Background() err := or.initPlugins(ctx) assert.EqualError(t, err, "pop") @@ -196,8 +196,9 @@ func TestInitPluginsDatabaseFail(t *testing.T) { func TestInitPluginsBlockchainFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, or.mmi).Return(fmt.Errorf("pop")) + or.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + or.mdi.On("RegisterListener", mock.Anything).Return() + or.mbi.On("Init", mock.Anything, mock.Anything, or.mmi).Return(fmt.Errorf("pop")) ctx := context.Background() err := or.initPlugins(ctx) assert.EqualError(t, err, "pop") @@ -206,8 +207,10 @@ func TestInitPluginsBlockchainFail(t *testing.T) { func TestInitPluginsDataexchangeNodesFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + or.mdi.On("RegisterListener", mock.Anything).Return() + or.mbi.On("Init", mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mbi.On("RegisterListener", mock.Anything).Return() or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("pop")) ctx := context.Background() err := or.initPlugins(ctx) @@ -217,10 +220,12 @@ func TestInitPluginsDataexchangeNodesFail(t *testing.T) { func TestInitPluginsDataexchangeFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + or.mdi.On("RegisterListener", mock.Anything).Return() + or.mbi.On("Init", mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mbi.On("RegisterListener", mock.Anything).Return() or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) - or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) ctx := context.Background() err := or.initPlugins(ctx) assert.EqualError(t, err, "pop") @@ -229,11 +234,14 @@ func TestInitPluginsDataexchangeFail(t *testing.T) { func TestInitPluginsSharedstorageFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + or.mdi.On("RegisterListener", mock.Anything).Return() + or.mbi.On("Init", mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mbi.On("RegisterListener", mock.Anything).Return() or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) - or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) - or.mps.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mdx.On("RegisterListener", mock.Anything).Return() + or.mps.On("Init", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) ctx := context.Background() err := or.initPlugins(ctx) assert.EqualError(t, err, "pop") @@ -242,11 +250,15 @@ func TestInitPluginsSharedstorageFail(t *testing.T) { func TestInitPluginsTokensFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + or.mdi.On("RegisterListener", mock.Anything).Return() + or.mbi.On("Init", mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mbi.On("RegisterListener", mock.Anything).Return() or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) - or.mdx.On("Init", mock.Anything, 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.mdx.On("RegisterListener", mock.Anything).Return() + or.mps.On("Init", mock.Anything, mock.Anything).Return(nil) + or.mps.On("RegisterListener", mock.Anything).Return() or.mti.On("Init", mock.Anything, "token", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) ctx := context.Background() err := or.initPlugins(ctx) @@ -256,12 +268,17 @@ func TestInitPluginsTokensFail(t *testing.T) { func TestInitAllPluginsOK(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - or.mbi.On("Init", mock.Anything, mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + or.mdi.On("RegisterListener", mock.Anything).Return() + or.mbi.On("Init", mock.Anything, mock.Anything, or.mmi).Return(nil) + or.mbi.On("RegisterListener", mock.Anything).Return() or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) - or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) - or.mps.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - or.mti.On("Init", mock.Anything, "token", mock.Anything, mock.Anything).Return(nil) + or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + or.mdx.On("RegisterListener", mock.Anything).Return() + or.mps.On("Init", mock.Anything, mock.Anything).Return(nil) + or.mps.On("RegisterListener", mock.Anything).Return() + or.mti.On("Init", mock.Anything, "token", mock.Anything).Return(nil) + or.mti.On("RegisterListener", mock.Anything).Return() err := or.Init(or.ctx, or.cancelCtx) assert.NoError(t, err) } @@ -476,7 +493,7 @@ func TestGetComponents(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + or.mdi.On("Init", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) ctx, cancelCtx := context.WithCancel(context.Background()) err := or.Init(ctx, cancelCtx) diff --git a/internal/sharedstorage/ipfs/ipfs.go b/internal/sharedstorage/ipfs/ipfs.go index 1bd1cf3f27..e9d4d12020 100644 --- a/internal/sharedstorage/ipfs/ipfs.go +++ b/internal/sharedstorage/ipfs/ipfs.go @@ -50,10 +50,9 @@ func (i *IPFS) Name() string { return "ipfs" } -func (i *IPFS) Init(ctx context.Context, config config.Section, callbacks sharedstorage.Callbacks) error { +func (i *IPFS) Init(ctx context.Context, config config.Section) error { i.ctx = log.WithLogField(ctx, "sharedstorage", "ipfs") - i.callbacks = callbacks apiConfig := config.SubSection(IPFSConfAPISubconf) if apiConfig.GetString(ffresty.HTTPConfigURL) == "" { @@ -69,6 +68,10 @@ func (i *IPFS) Init(ctx context.Context, config config.Section, callbacks shared return nil } +func (i *IPFS) RegisterListener(callbacks sharedstorage.Callbacks) { + i.callbacks = callbacks +} + func (i *IPFS) Capabilities() *sharedstorage.Capabilities { return i.capabilities } diff --git a/internal/sharedstorage/ipfs/ipfs_test.go b/internal/sharedstorage/ipfs/ipfs_test.go index 6634c0d25d..1d3d98e84f 100644 --- a/internal/sharedstorage/ipfs/ipfs_test.go +++ b/internal/sharedstorage/ipfs/ipfs_test.go @@ -28,7 +28,6 @@ import ( "github.com/hyperledger/firefly-common/pkg/ffresty" "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly/internal/coreconfig" - "github.com/hyperledger/firefly/mocks/sharedstoragemocks" "github.com/jarcoal/httpmock" "github.com/stretchr/testify/assert" ) @@ -46,7 +45,7 @@ func TestInitMissingAPIURL(t *testing.T) { resetConf() utConfig.SubSection(IPFSConfGatewaySubconf).Set(ffresty.HTTPConfigURL, "http://localhost:12345") - err := i.Init(context.Background(), utConfig, &sharedstoragemocks.Callbacks{}) + err := i.Init(context.Background(), utConfig) assert.Regexp(t, "FF10138", err) } @@ -55,7 +54,7 @@ func TestInitMissingGWURL(t *testing.T) { resetConf() utConfig.SubSection(IPFSConfAPISubconf).Set(ffresty.HTTPConfigURL, "http://localhost:12345") - err := i.Init(context.Background(), utConfig, &sharedstoragemocks.Callbacks{}) + err := i.Init(context.Background(), utConfig) assert.Regexp(t, "FF10138", err) } @@ -65,7 +64,7 @@ func TestInit(t *testing.T) { utConfig.SubSection(IPFSConfAPISubconf).Set(ffresty.HTTPConfigURL, "http://localhost:12345") utConfig.SubSection(IPFSConfGatewaySubconf).Set(ffresty.HTTPConfigURL, "http://localhost:12345") - err := i.Init(context.Background(), utConfig, &sharedstoragemocks.Callbacks{}) + err := i.Init(context.Background(), utConfig) assert.Equal(t, "ipfs", i.Name()) assert.NoError(t, err) assert.NotNil(t, i.Capabilities()) @@ -83,7 +82,7 @@ func TestIPFSUploadSuccess(t *testing.T) { utConfig.SubSection(IPFSConfGatewaySubconf).Set(ffresty.HTTPConfigURL, "http://localhost:12345") utConfig.SubSection(IPFSConfAPISubconf).Set(ffresty.HTTPCustomClient, mockedClient) - err := i.Init(context.Background(), utConfig, &sharedstoragemocks.Callbacks{}) + err := i.Init(context.Background(), utConfig) assert.NoError(t, err) httpmock.RegisterResponder("POST", "http://localhost:12345/api/v0/add", @@ -110,7 +109,7 @@ func TestIPFSUploadFail(t *testing.T) { utConfig.SubSection(IPFSConfGatewaySubconf).Set(ffresty.HTTPConfigURL, "http://localhost:12345") utConfig.SubSection(IPFSConfAPISubconf).Set(ffresty.HTTPCustomClient, mockedClient) - err := i.Init(context.Background(), utConfig, &sharedstoragemocks.Callbacks{}) + err := i.Init(context.Background(), utConfig) assert.NoError(t, err) httpmock.RegisterResponder("POST", "http://localhost:12345/api/v0/add", @@ -134,7 +133,7 @@ func TestIPFSDownloadSuccess(t *testing.T) { utConfig.SubSection(IPFSConfGatewaySubconf).Set(ffresty.HTTPConfigURL, "http://localhost:12345") utConfig.SubSection(IPFSConfGatewaySubconf).Set(ffresty.HTTPCustomClient, mockedClient) - err := i.Init(context.Background(), utConfig, &sharedstoragemocks.Callbacks{}) + err := i.Init(context.Background(), utConfig) assert.NoError(t, err) data := []byte(`{"hello": "world"}`) @@ -163,7 +162,7 @@ func TestIPFSDownloadFail(t *testing.T) { utConfig.SubSection(IPFSConfGatewaySubconf).Set(ffresty.HTTPConfigURL, "http://localhost:12345") utConfig.SubSection(IPFSConfGatewaySubconf).Set(ffresty.HTTPCustomClient, mockedClient) - err := i.Init(context.Background(), utConfig, &sharedstoragemocks.Callbacks{}) + err := i.Init(context.Background(), utConfig) assert.NoError(t, err) httpmock.RegisterResponder("GET", "http://localhost:12345/ipfs/QmRAQfHNnknnz8S936M2yJGhhVNA6wXJ4jTRP3VXtptmmL", @@ -186,7 +185,7 @@ func TestIPFSDownloadError(t *testing.T) { utConfig.SubSection(IPFSConfGatewaySubconf).Set(ffresty.HTTPConfigURL, "http://localhost:12345") utConfig.SubSection(IPFSConfGatewaySubconf).Set(ffresty.HTTPCustomClient, mockedClient) - err := i.Init(context.Background(), utConfig, &sharedstoragemocks.Callbacks{}) + err := i.Init(context.Background(), utConfig) assert.NoError(t, err) httpmock.RegisterResponder("GET", "http://localhost:12345/ipfs/QmRAQfHNnknnz8S936M2yJGhhVNA6wXJ4jTRP3VXtptmmL", diff --git a/internal/tokens/fftokens/fftokens.go b/internal/tokens/fftokens/fftokens.go index 4b04da3776..1cd931f316 100644 --- a/internal/tokens/fftokens/fftokens.go +++ b/internal/tokens/fftokens/fftokens.go @@ -132,9 +132,8 @@ func (ft *FFTokens) Name() string { return "fftokens" } -func (ft *FFTokens) Init(ctx context.Context, name string, config config.Section, callbacks tokens.Callbacks) (err error) { +func (ft *FFTokens) Init(ctx context.Context, name string, config config.Section) (err error) { ft.ctx = log.WithLogField(ctx, "proto", "fftokens") - ft.callbacks = callbacks ft.configuredName = name if config.GetString(ffresty.HTTPConfigURL) == "" { @@ -160,6 +159,10 @@ func (ft *FFTokens) Init(ctx context.Context, name string, config config.Section return nil } +func (ft *FFTokens) RegisterListener(callbacks tokens.Callbacks) { + ft.callbacks = callbacks +} + func (ft *FFTokens) Start() error { return ft.wsconn.Connect() } diff --git a/internal/tokens/fftokens/fftokens_test.go b/internal/tokens/fftokens/fftokens_test.go index d2fc982a27..6d6bcc18dd 100644 --- a/internal/tokens/fftokens/fftokens_test.go +++ b/internal/tokens/fftokens/fftokens_test.go @@ -60,7 +60,7 @@ func newTestFFTokens(t *testing.T) (h *FFTokens, toServer, fromServer chan strin ffTokensConfig.AddKnownKey(ffresty.HTTPCustomClient, mockedClient) config.Set("tokens", []fftypes.JSONObject{{}}) - err := h.Init(context.Background(), "testtokens", ffTokensConfig, &tokenmocks.Callbacks{}) + err := h.Init(context.Background(), "testtokens", ffTokensConfig) assert.NoError(t, err) assert.Equal(t, "fftokens", h.Name()) assert.Equal(t, "testtokens", h.configuredName) @@ -77,7 +77,7 @@ func TestInitBadURL(t *testing.T) { h.InitConfig(ffTokensConfig) ffTokensConfig.AddKnownKey(ffresty.HTTPConfigURL, "::::////") - err := h.Init(context.Background(), "testtokens", ffTokensConfig, &tokenmocks.Callbacks{}) + err := h.Init(context.Background(), "testtokens", ffTokensConfig) assert.Regexp(t, "FF00149", err) } @@ -86,7 +86,7 @@ func TestInitMissingURL(t *testing.T) { h := &FFTokens{} h.InitConfig(ffTokensConfig) - err := h.Init(context.Background(), "testtokens", ffTokensConfig, &tokenmocks.Callbacks{}) + err := h.Init(context.Background(), "testtokens", ffTokensConfig) assert.Regexp(t, "FF10138", err) } @@ -259,7 +259,8 @@ func TestCreateTokenPoolSynchronous(t *testing.T) { return res, nil }) - mcb := h.callbacks.(*tokenmocks.Callbacks) + mcb := &tokenmocks.Callbacks{} + h.callbacks = mcb mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { return p.PoolLocator == "F1" && p.Type == core.TokenTypeFungible && *p.TX.ID == *pool.TX.ID })).Return(nil) @@ -412,7 +413,8 @@ func TestActivateTokenPoolSynchronous(t *testing.T) { return res, nil }) - mcb := h.callbacks.(*tokenmocks.Callbacks) + mcb := &tokenmocks.Callbacks{} + h.callbacks = mcb mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { return p.PoolLocator == "F1" && p.Type == core.TokenTypeFungible && p.TX.ID == nil && p.Event.ProtocolID == "" })).Return(nil) @@ -457,7 +459,8 @@ func TestActivateTokenPoolSynchronousBadResponse(t *testing.T) { return res, nil }) - mcb := h.callbacks.(*tokenmocks.Callbacks) + mcb := &tokenmocks.Callbacks{} + h.callbacks = mcb mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { return p.PoolLocator == "F1" && p.Type == core.TokenTypeFungible && p.TX.ID == nil })).Return(nil) @@ -776,7 +779,8 @@ func TestEvents(t *testing.T) { msg := <-toServer assert.Equal(t, `{"data":{"id":"1"},"event":"ack"}`, string(msg)) - mcb := h.callbacks.(*tokenmocks.Callbacks) + mcb := &tokenmocks.Callbacks{} + h.callbacks = mcb opID := fftypes.NewUUID() txID := fftypes.NewUUID() diff --git a/mocks/blockchainmocks/plugin.go b/mocks/blockchainmocks/plugin.go index f59607144d..890424ea26 100644 --- a/mocks/blockchainmocks/plugin.go +++ b/mocks/blockchainmocks/plugin.go @@ -140,13 +140,13 @@ func (_m *Plugin) GetFFIParamValidator(ctx context.Context) (core.FFIParamValida return r0, r1 } -// Init provides a mock function with given fields: ctx, _a1, callbacks, _a3 -func (_m *Plugin) Init(ctx context.Context, _a1 config.Section, callbacks blockchain.Callbacks, _a3 metrics.Manager) error { - ret := _m.Called(ctx, _a1, callbacks, _a3) +// Init provides a mock function with given fields: ctx, _a1, _a2 +func (_m *Plugin) Init(ctx context.Context, _a1 config.Section, _a2 metrics.Manager) error { + ret := _m.Called(ctx, _a1, _a2) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, config.Section, blockchain.Callbacks, metrics.Manager) error); ok { - r0 = rf(ctx, _a1, callbacks, _a3) + if rf, ok := ret.Get(0).(func(context.Context, config.Section, metrics.Manager) error); ok { + r0 = rf(ctx, _a1, _a2) } else { r0 = ret.Error(0) } @@ -268,6 +268,11 @@ func (_m *Plugin) QueryContract(ctx context.Context, location *fftypes.JSONAny, return r0, r1 } +// RegisterListener provides a mock function with given fields: callbacks +func (_m *Plugin) RegisterListener(callbacks blockchain.Callbacks) { + _m.Called(callbacks) +} + // Start provides a mock function with given fields: func (_m *Plugin) Start() error { ret := _m.Called() diff --git a/mocks/databasemocks/plugin.go b/mocks/databasemocks/plugin.go index 1bfc4c6af9..0b8066bbe1 100644 --- a/mocks/databasemocks/plugin.go +++ b/mocks/databasemocks/plugin.go @@ -2259,13 +2259,13 @@ func (_m *Plugin) GetVerifiers(ctx context.Context, filter database.Filter) ([]* return r0, r1, r2 } -// Init provides a mock function with given fields: ctx, _a1, callbacks -func (_m *Plugin) Init(ctx context.Context, _a1 config.Section, callbacks database.Callbacks) error { - ret := _m.Called(ctx, _a1, callbacks) +// Init provides a mock function with given fields: ctx, _a1 +func (_m *Plugin) Init(ctx context.Context, _a1 config.Section) error { + ret := _m.Called(ctx, _a1) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, config.Section, database.Callbacks) error); ok { - r0 = rf(ctx, _a1, callbacks) + if rf, ok := ret.Get(0).(func(context.Context, config.Section) error); ok { + r0 = rf(ctx, _a1) } else { r0 = ret.Error(0) } @@ -2474,6 +2474,11 @@ func (_m *Plugin) Name() string { return r0 } +// RegisterListener provides a mock function with given fields: callbacks +func (_m *Plugin) RegisterListener(callbacks database.Callbacks) { + _m.Called(callbacks) +} + // ReplaceMessage provides a mock function with given fields: ctx, message func (_m *Plugin) ReplaceMessage(ctx context.Context, message *core.Message) error { ret := _m.Called(ctx, message) diff --git a/mocks/dataexchangemocks/plugin.go b/mocks/dataexchangemocks/plugin.go index 7b86173208..4c53d8c4df 100644 --- a/mocks/dataexchangemocks/plugin.go +++ b/mocks/dataexchangemocks/plugin.go @@ -127,13 +127,13 @@ func (_m *Plugin) GetEndpointInfo(ctx context.Context) (fftypes.JSONObject, erro return r0, r1 } -// Init provides a mock function with given fields: ctx, _a1, nodes, callbacks -func (_m *Plugin) Init(ctx context.Context, _a1 config.Section, nodes []fftypes.JSONObject, callbacks dataexchange.Callbacks) error { - ret := _m.Called(ctx, _a1, nodes, callbacks) +// Init provides a mock function with given fields: ctx, _a1, nodes +func (_m *Plugin) Init(ctx context.Context, _a1 config.Section, nodes []fftypes.JSONObject) error { + ret := _m.Called(ctx, _a1, nodes) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, config.Section, []fftypes.JSONObject, dataexchange.Callbacks) error); ok { - r0 = rf(ctx, _a1, nodes, callbacks) + if rf, ok := ret.Get(0).(func(context.Context, config.Section, []fftypes.JSONObject) error); ok { + r0 = rf(ctx, _a1, nodes) } else { r0 = ret.Error(0) } @@ -160,6 +160,11 @@ func (_m *Plugin) Name() string { return r0 } +// RegisterListener provides a mock function with given fields: callbacks +func (_m *Plugin) RegisterListener(callbacks dataexchange.Callbacks) { + _m.Called(callbacks) +} + // SendMessage provides a mock function with given fields: ctx, nsOpID, peerID, data func (_m *Plugin) SendMessage(ctx context.Context, nsOpID string, peerID string, data []byte) error { ret := _m.Called(ctx, nsOpID, peerID, data) diff --git a/mocks/identitymocks/plugin.go b/mocks/identitymocks/plugin.go index b0ed2ce43d..d739d8d0d3 100644 --- a/mocks/identitymocks/plugin.go +++ b/mocks/identitymocks/plugin.go @@ -33,13 +33,13 @@ func (_m *Plugin) Capabilities() *identity.Capabilities { return r0 } -// Init provides a mock function with given fields: ctx, _a1, callbacks -func (_m *Plugin) Init(ctx context.Context, _a1 config.Section, callbacks identity.Callbacks) error { - ret := _m.Called(ctx, _a1, callbacks) +// Init provides a mock function with given fields: ctx, _a1 +func (_m *Plugin) Init(ctx context.Context, _a1 config.Section) error { + ret := _m.Called(ctx, _a1) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, config.Section, identity.Callbacks) error); ok { - r0 = rf(ctx, _a1, callbacks) + if rf, ok := ret.Get(0).(func(context.Context, config.Section) error); ok { + r0 = rf(ctx, _a1) } else { r0 = ret.Error(0) } @@ -66,6 +66,11 @@ func (_m *Plugin) Name() string { return r0 } +// RegisterListener provides a mock function with given fields: callbacks +func (_m *Plugin) RegisterListener(callbacks identity.Callbacks) { + _m.Called(callbacks) +} + // Start provides a mock function with given fields: func (_m *Plugin) Start() error { ret := _m.Called() diff --git a/mocks/sharedstoragemocks/plugin.go b/mocks/sharedstoragemocks/plugin.go index f07688cf39..c6fc4c85fa 100644 --- a/mocks/sharedstoragemocks/plugin.go +++ b/mocks/sharedstoragemocks/plugin.go @@ -58,13 +58,13 @@ func (_m *Plugin) DownloadData(ctx context.Context, payloadRef string) (io.ReadC return r0, r1 } -// Init provides a mock function with given fields: ctx, _a1, callbacks -func (_m *Plugin) Init(ctx context.Context, _a1 config.Section, callbacks sharedstorage.Callbacks) error { - ret := _m.Called(ctx, _a1, callbacks) +// Init provides a mock function with given fields: ctx, _a1 +func (_m *Plugin) Init(ctx context.Context, _a1 config.Section) error { + ret := _m.Called(ctx, _a1) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, config.Section, sharedstorage.Callbacks) error); ok { - r0 = rf(ctx, _a1, callbacks) + if rf, ok := ret.Get(0).(func(context.Context, config.Section) error); ok { + r0 = rf(ctx, _a1) } else { r0 = ret.Error(0) } @@ -91,6 +91,11 @@ func (_m *Plugin) Name() string { return r0 } +// RegisterListener provides a mock function with given fields: callbacks +func (_m *Plugin) RegisterListener(callbacks sharedstorage.Callbacks) { + _m.Called(callbacks) +} + // UploadData provides a mock function with given fields: ctx, data func (_m *Plugin) UploadData(ctx context.Context, data io.Reader) (string, error) { ret := _m.Called(ctx, data) diff --git a/mocks/tokenmocks/plugin.go b/mocks/tokenmocks/plugin.go index 0443217b27..f389bf4924 100644 --- a/mocks/tokenmocks/plugin.go +++ b/mocks/tokenmocks/plugin.go @@ -91,13 +91,13 @@ func (_m *Plugin) CreateTokenPool(ctx context.Context, nsOpID string, pool *core return r0, r1 } -// Init provides a mock function with given fields: ctx, name, _a2, callbacks -func (_m *Plugin) Init(ctx context.Context, name string, _a2 config.Section, callbacks tokens.Callbacks) error { - ret := _m.Called(ctx, name, _a2, callbacks) +// Init provides a mock function with given fields: ctx, name, _a2 +func (_m *Plugin) Init(ctx context.Context, name string, _a2 config.Section) error { + ret := _m.Called(ctx, name, _a2) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, config.Section, tokens.Callbacks) error); ok { - r0 = rf(ctx, name, _a2, callbacks) + if rf, ok := ret.Get(0).(func(context.Context, string, config.Section) error); ok { + r0 = rf(ctx, name, _a2) } else { r0 = ret.Error(0) } @@ -138,6 +138,11 @@ func (_m *Plugin) Name() string { return r0 } +// RegisterListener provides a mock function with given fields: callbacks +func (_m *Plugin) RegisterListener(callbacks tokens.Callbacks) { + _m.Called(callbacks) +} + // Start provides a mock function with given fields: func (_m *Plugin) Start() error { ret := _m.Called() diff --git a/pkg/blockchain/plugin.go b/pkg/blockchain/plugin.go index 1de453d529..219e48766f 100644 --- a/pkg/blockchain/plugin.go +++ b/pkg/blockchain/plugin.go @@ -33,7 +33,10 @@ type Plugin interface { InitConfig(config config.Section) // Init initializes the plugin, with configuration - Init(ctx context.Context, config config.Section, callbacks Callbacks, metrics metrics.Manager) error + Init(ctx context.Context, config config.Section, metrics metrics.Manager) error + + // RegisterListener registers a listener to receive callbacks + RegisterListener(callbacks Callbacks) // ConfigureContract initializes the subscription to the FireFly contract // - Checks the provided contract info against the plugin's configuration, and updates it as needed diff --git a/pkg/database/plugin.go b/pkg/database/plugin.go index d761d6e831..a064b70756 100644 --- a/pkg/database/plugin.go +++ b/pkg/database/plugin.go @@ -51,8 +51,10 @@ type Plugin interface { InitConfig(config config.Section) // Init initializes the plugin, with configuration - // Returns the supported featureset of the interface - Init(ctx context.Context, config config.Section, callbacks Callbacks) error + Init(ctx context.Context, config config.Section) error + + // RegisterListener registers a listener to receive callbacks + RegisterListener(callbacks Callbacks) // Capabilities returns capabilities - not called until after Init Capabilities() *Capabilities diff --git a/pkg/dataexchange/plugin.go b/pkg/dataexchange/plugin.go index 19879ccb05..88d74df3e1 100644 --- a/pkg/dataexchange/plugin.go +++ b/pkg/dataexchange/plugin.go @@ -61,7 +61,10 @@ type Plugin interface { InitConfig(config config.Section) // Init initializes the plugin, with configuration - Init(ctx context.Context, config config.Section, nodes []fftypes.JSONObject, callbacks Callbacks) error + Init(ctx context.Context, config config.Section, nodes []fftypes.JSONObject) error + + // RegisterListener registers a listener to receive callbacks + RegisterListener(callbacks Callbacks) // Data exchange interface must not deliver any events until start is called Start() error diff --git a/pkg/identity/plugin.go b/pkg/identity/plugin.go index ae870cd43d..6f250e6002 100644 --- a/pkg/identity/plugin.go +++ b/pkg/identity/plugin.go @@ -31,8 +31,10 @@ type Plugin interface { InitConfig(config config.Section) // Init initializes the plugin, with configuration - // Returns the supported featureset of the interface - Init(ctx context.Context, config config.Section, callbacks Callbacks) error + Init(ctx context.Context, config config.Section) error + + // RegisterListener registers a listener to receive callbacks + RegisterListener(callbacks Callbacks) // Blockchain interface must not deliver any events until start is called Start() error diff --git a/pkg/sharedstorage/plugin.go b/pkg/sharedstorage/plugin.go index f3de137aa4..1045353ea5 100644 --- a/pkg/sharedstorage/plugin.go +++ b/pkg/sharedstorage/plugin.go @@ -32,8 +32,10 @@ type Plugin interface { InitConfig(config config.Section) // Init initializes the plugin, with configuration - // Returns the supported featureset of the interface - Init(ctx context.Context, config config.Section, callbacks Callbacks) error + Init(ctx context.Context, config config.Section) error + + // RegisterListener registers a listener to receive callbacks + RegisterListener(callbacks Callbacks) // Capabilities returns capabilities - not called until after Init Capabilities() *Capabilities diff --git a/pkg/tokens/plugin.go b/pkg/tokens/plugin.go index a62922308d..1ca4e922d8 100644 --- a/pkg/tokens/plugin.go +++ b/pkg/tokens/plugin.go @@ -33,8 +33,10 @@ type Plugin interface { InitConfig(config config.KeySet) // Init initializes the plugin, with configuration - // Returns the supported featureset of the interface - Init(ctx context.Context, name string, config config.Section, callbacks Callbacks) error + Init(ctx context.Context, name string, config config.Section) error + + // RegisterListener registers a listener to receive callbacks + RegisterListener(callbacks Callbacks) // Blockchain interface must not deliver any events until start is called Start() error From 9f6be1899eacb8d82637ef76c64ab65899e87500 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Wed, 8 Jun 2022 16:46:39 -0400 Subject: [PATCH 20/33] Move plugin init to namespace manager Signed-off-by: Andrew Richardson --- internal/dataexchange/ffdx/ffdx.go | 8 +- internal/dataexchange/ffdx/ffdx_test.go | 12 ++- internal/namespace/manager.go | 32 +++++++ internal/namespace/manager_test.go | 68 +++++++++------ internal/orchestrator/orchestrator.go | 20 +---- internal/orchestrator/orchestrator_test.go | 98 +--------------------- mocks/dataexchangemocks/plugin.go | 15 ++-- pkg/dataexchange/plugin.go | 5 +- 8 files changed, 100 insertions(+), 158 deletions(-) diff --git a/internal/dataexchange/ffdx/ffdx.go b/internal/dataexchange/ffdx/ffdx.go index 8f3924a368..1447a27933 100644 --- a/internal/dataexchange/ffdx/ffdx.go +++ b/internal/dataexchange/ffdx/ffdx.go @@ -108,7 +108,7 @@ func (h *FFDX) Name() string { return "ffdx" } -func (h *FFDX) Init(ctx context.Context, config config.Section, nodes []fftypes.JSONObject) (err error) { +func (h *FFDX) Init(ctx context.Context, config config.Section) (err error) { h.ctx = log.WithLogField(ctx, "dx", "https") h.ackChannel = make(chan *ack) @@ -118,8 +118,6 @@ func (h *FFDX) Init(ctx context.Context, config config.Section, nodes []fftypes. return i18n.NewError(ctx, coremsgs.MsgMissingPluginConfig, "url", "dataexchange.ffdx") } - h.nodes = nodes - h.client = ffresty.New(h.ctx, config) h.capabilities = &dataexchange.Capabilities{ Manifest: config.GetBool(DataExchangeManifestEnabled), @@ -136,6 +134,10 @@ func (h *FFDX) Init(ctx context.Context, config config.Section, nodes []fftypes. return nil } +func (h *FFDX) SetNodes(nodes []fftypes.JSONObject) { + h.nodes = nodes +} + func (h *FFDX) RegisterListener(callbacks dataexchange.Callbacks) { h.callbacks = callbacks } diff --git a/internal/dataexchange/ffdx/ffdx_test.go b/internal/dataexchange/ffdx/ffdx_test.go index 2dfdb294c0..04281bdbfc 100644 --- a/internal/dataexchange/ffdx/ffdx_test.go +++ b/internal/dataexchange/ffdx/ffdx_test.go @@ -59,11 +59,10 @@ func newTestFFDX(t *testing.T, manifestEnabled bool) (h *FFDX, toServer, fromSer utConfig.Set(DataExchangeManifestEnabled, manifestEnabled) h = &FFDX{initialized: true} - nodes := make([]fftypes.JSONObject, 0) h.InitConfig(utConfig) dxCtx, dxCancel := context.WithCancel(context.Background()) - err := h.Init(dxCtx, utConfig, nodes) + err := h.Init(dxCtx, utConfig) assert.NoError(t, err) assert.Equal(t, "ffdx", h.Name()) assert.NotNil(t, h.Capabilities()) @@ -77,19 +76,17 @@ func newTestFFDX(t *testing.T, manifestEnabled bool) (h *FFDX, toServer, fromSer func TestInitBadURL(t *testing.T) { coreconfig.Reset() h := &FFDX{} - nodes := make([]fftypes.JSONObject, 0) h.InitConfig(utConfig) utConfig.Set(ffresty.HTTPConfigURL, "::::////") - err := h.Init(context.Background(), utConfig, nodes) + err := h.Init(context.Background(), utConfig) assert.Regexp(t, "FF00149", err) } func TestInitMissingURL(t *testing.T) { coreconfig.Reset() h := &FFDX{} - nodes := make([]fftypes.JSONObject, 0) h.InitConfig(utConfig) - err := h.Init(context.Background(), utConfig, nodes) + err := h.Init(context.Background(), utConfig) assert.Regexp(t, "FF10138", err) } @@ -681,8 +678,9 @@ func TestWebsocketWithReinit(t *testing.T) { }) h.InitConfig(utConfig) - err := h.Init(context.Background(), utConfig, nodes) + err := h.Init(context.Background(), utConfig) assert.NoError(t, err) + h.SetNodes(nodes) err = h.Start() assert.NoError(t, err) diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index 96781b5f0b..8f294d3010 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -123,6 +123,9 @@ func (nm *namespaceManager) Init(ctx context.Context, cancelCtx context.CancelFu if err = nm.loadPlugins(ctx); err != nil { return err } + if err = nm.initPlugins(ctx); err != nil { + return err + } if err = nm.loadNamespaces(ctx); err != nil { return err } @@ -537,6 +540,35 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin return plugins, err } +func (nm *namespaceManager) initPlugins(ctx context.Context) (err error) { + for _, plugin := range nm.plugins.database { + if err = plugin.Plugin.Init(ctx, plugin.Config); err != nil { + return err + } + } + for _, plugin := range nm.plugins.blockchain { + if err = plugin.Plugin.Init(ctx, plugin.Config, nm.metrics); err != nil { + return err + } + } + for _, plugin := range nm.plugins.dataexchange { + if err = plugin.Plugin.Init(ctx, plugin.Config); err != nil { + return err + } + } + for _, plugin := range nm.plugins.sharedstorage { + if err = plugin.Plugin.Init(ctx, plugin.Config); err != nil { + return err + } + } + for _, plugin := range nm.plugins.tokens { + if err = plugin.Plugin.Init(ctx, plugin.Name, plugin.Config); err != nil { + return err + } + } + return nil +} + func (nm *namespaceManager) loadNamespaces(ctx context.Context) (err error) { defaultNS := config.GetString(coreconfig.NamespacesDefault) size := namespacePredefined.ArraySize() diff --git a/internal/namespace/manager_test.go b/internal/namespace/manager_test.go index 1c5e41834a..e727aa2161 100644 --- a/internal/namespace/manager_test.go +++ b/internal/namespace/manager_test.go @@ -53,9 +53,21 @@ type testNamespaceManager struct { namespaceManager mmi *metricsmocks.Manager mae *spieventsmocks.Manager + mbi *blockchainmocks.Plugin + mdi *databasemocks.Plugin + mdx *dataexchangemocks.Plugin + mps *sharedstoragemocks.Plugin + mti *tokenmocks.Plugin } func (nm *testNamespaceManager) cleanup(t *testing.T) { + nm.mmi.AssertExpectations(t) + nm.mae.AssertExpectations(t) + nm.mbi.AssertExpectations(t) + nm.mdi.AssertExpectations(t) + nm.mdx.AssertExpectations(t) + nm.mps.AssertExpectations(t) + nm.mti.AssertExpectations(t) } func newTestNamespaceManager(resetConfig bool) *testNamespaceManager { @@ -67,28 +79,33 @@ func newTestNamespaceManager(resetConfig bool) *testNamespaceManager { nm := &testNamespaceManager{ mmi: &metricsmocks.Manager{}, mae: &spieventsmocks.Manager{}, + mbi: &blockchainmocks.Plugin{}, + mdi: &databasemocks.Plugin{}, + mdx: &dataexchangemocks.Plugin{}, + mps: &sharedstoragemocks.Plugin{}, + mti: &tokenmocks.Plugin{}, namespaceManager: namespaceManager{ namespaces: make(map[string]*namespace), pluginNames: make(map[string]bool), }, } nm.plugins.blockchain = map[string]orchestrator.BlockchainPlugin{ - "ethereum": {Plugin: &blockchainmocks.Plugin{}}, + "ethereum": {Plugin: nm.mbi}, } nm.plugins.database = map[string]orchestrator.DatabasePlugin{ - "postgres": {Plugin: &databasemocks.Plugin{}}, + "postgres": {Plugin: nm.mdi}, } nm.plugins.dataexchange = map[string]orchestrator.DataExchangePlugin{ - "ffdx": {Plugin: &dataexchangemocks.Plugin{}}, + "ffdx": {Plugin: nm.mdx}, } nm.plugins.sharedstorage = map[string]orchestrator.SharedStoragePlugin{ - "ipfs": {Plugin: &sharedstoragemocks.Plugin{}}, + "ipfs": {Plugin: nm.mps}, } nm.plugins.identity = map[string]orchestrator.IdentityPlugin{ "tbd": {Plugin: &identitymocks.Plugin{}}, } nm.plugins.tokens = map[string]orchestrator.TokensPlugin{ - "erc721": {Plugin: &tokenmocks.Plugin{}}, + "erc721": {Plugin: nm.mti}, } nm.namespaceManager.metrics = nm.mmi nm.namespaceManager.adminEvents = nm.mae @@ -108,8 +125,12 @@ func TestInit(t *testing.T) { mo.On("Init", mock.Anything, mock.Anything).Return(nil) nm.utOrchestrator = mo - mbi := nm.plugins.blockchain["ethereum"].Plugin.(*blockchainmocks.Plugin) - mbi.On("NetworkVersion").Return(2) + nm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mbi.On("Init", mock.Anything, mock.Anything, nm.mmi).Return(nil) + nm.mdx.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mps.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mti.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + nm.mbi.On("NetworkVersion").Return(2) ctx, cancelCtx := context.WithCancel(context.Background()) err := nm.Init(ctx, cancelCtx) @@ -128,8 +149,12 @@ func TestInitVersion1(t *testing.T) { mo.On("Init", mock.Anything, mock.Anything).Return(nil).Once() nm.utOrchestrator = mo - mbi := nm.plugins.blockchain["ethereum"].Plugin.(*blockchainmocks.Plugin) - mbi.On("NetworkVersion").Return(1) + nm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mbi.On("Init", mock.Anything, mock.Anything, nm.mmi).Return(nil) + nm.mdx.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mps.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mti.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + nm.mbi.On("NetworkVersion").Return(1) ctx, cancelCtx := context.WithCancel(context.Background()) err := nm.Init(ctx, cancelCtx) @@ -149,28 +174,18 @@ func TestInitVersion1Fail(t *testing.T) { mo.On("Init", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")).Once() nm.utOrchestrator = mo - mbi := nm.plugins.blockchain["ethereum"].Plugin.(*blockchainmocks.Plugin) - mbi.On("NetworkVersion").Return(1) + nm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mbi.On("Init", mock.Anything, mock.Anything, nm.mmi).Return(nil) + nm.mdx.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mps.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mti.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + nm.mbi.On("NetworkVersion").Return(1) ctx, cancelCtx := context.WithCancel(context.Background()) err := nm.Init(ctx, cancelCtx) assert.EqualError(t, err, "pop") } -func TestInitFail(t *testing.T) { - nm := newTestNamespaceManager(true) - defer nm.cleanup(t) - - mdi := nm.plugins.database["postgres"].Plugin.(*databasemocks.Plugin) - mdi.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - - ctx, cancelCtx := context.WithCancel(context.Background()) - err := nm.Init(ctx, cancelCtx) - assert.EqualError(t, err, "pop") - - mdi.AssertExpectations(t) -} - func TestDeprecatedDatabasePlugin(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -610,8 +625,7 @@ func TestInitNamespacesNoDefault(t *testing.T) { `)) assert.NoError(t, err) - ctx, cancelCtx := context.WithCancel(context.Background()) - err = nm.Init(ctx, cancelCtx) + err = nm.loadNamespaces(context.Background()) assert.Regexp(t, "FF10166", err) } diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index c7f6e0f5d7..e3e8c6448f 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -367,14 +367,7 @@ func (or *orchestrator) Operations() operations.Manager { } func (or *orchestrator) initPlugins(ctx context.Context) (err error) { - if err = or.plugins.Database.Plugin.Init(ctx, or.plugins.Database.Config); err != nil { - return err - } or.plugins.Database.Plugin.RegisterListener(or) - - if err = or.plugins.Blockchain.Plugin.Init(ctx, or.plugins.Blockchain.Config, or.metrics); err != nil { - return err - } or.plugins.Blockchain.Plugin.RegisterListener(&or.bc) fb := database.IdentityQueryFactory.NewFilter(ctx) @@ -388,25 +381,16 @@ func (or *orchestrator) initPlugins(ctx context.Context) (err error) { for i, node := range nodes { nodeInfo[i] = node.Profile } - - if err = or.plugins.DataExchange.Plugin.Init(ctx, or.plugins.DataExchange.Config, nodeInfo); err != nil { - return err - } + or.plugins.DataExchange.Plugin.SetNodes(nodeInfo) or.plugins.DataExchange.Plugin.RegisterListener(&or.bc) - if err = or.plugins.SharedStorage.Plugin.Init(ctx, or.plugins.SharedStorage.Config); err != nil { - return err - } or.plugins.SharedStorage.Plugin.RegisterListener(&or.bc) for _, token := range or.plugins.Tokens { - if err = token.Plugin.Init(ctx, token.Name, token.Config); err != nil { - return err - } token.Plugin.RegisterListener(&or.bc) } - return err + return nil } func (or *orchestrator) initComponents(ctx context.Context) (err error) { diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index 32fd67b676..e3581bdf1b 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -184,32 +184,10 @@ func TestNewOrchestrator(t *testing.T) { assert.NotNil(t, or) } -func TestInitPluginsDatabaseFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - ctx := context.Background() - err := or.initPlugins(ctx) - assert.EqualError(t, err, "pop") -} - -func TestInitPluginsBlockchainFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) - or.mdi.On("RegisterListener", mock.Anything).Return() - or.mbi.On("Init", mock.Anything, mock.Anything, or.mmi).Return(fmt.Errorf("pop")) - ctx := context.Background() - err := or.initPlugins(ctx) - assert.EqualError(t, err, "pop") -} - func TestInitPluginsDataexchangeNodesFail(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) or.mdi.On("RegisterListener", mock.Anything).Return() - or.mbi.On("Init", mock.Anything, mock.Anything, or.mmi).Return(nil) or.mbi.On("RegisterListener", mock.Anything).Return() or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("pop")) ctx := context.Background() @@ -217,67 +195,15 @@ func TestInitPluginsDataexchangeNodesFail(t *testing.T) { assert.EqualError(t, err, "pop") } -func TestInitPluginsDataexchangeFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) - or.mdi.On("RegisterListener", mock.Anything).Return() - or.mbi.On("Init", mock.Anything, mock.Anything, or.mmi).Return(nil) - or.mbi.On("RegisterListener", mock.Anything).Return() - or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) - or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - ctx := context.Background() - err := or.initPlugins(ctx) - assert.EqualError(t, err, "pop") -} - -func TestInitPluginsSharedstorageFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) - or.mdi.On("RegisterListener", mock.Anything).Return() - or.mbi.On("Init", mock.Anything, mock.Anything, or.mmi).Return(nil) - or.mbi.On("RegisterListener", mock.Anything).Return() - or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) - or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - or.mdx.On("RegisterListener", mock.Anything).Return() - or.mps.On("Init", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - ctx := context.Background() - err := or.initPlugins(ctx) - assert.EqualError(t, err, "pop") -} - -func TestInitPluginsTokensFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) - or.mdi.On("RegisterListener", mock.Anything).Return() - or.mbi.On("Init", mock.Anything, mock.Anything, or.mmi).Return(nil) - or.mbi.On("RegisterListener", mock.Anything).Return() - or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) - or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) - or.mdx.On("RegisterListener", mock.Anything).Return() - or.mps.On("Init", mock.Anything, mock.Anything).Return(nil) - or.mps.On("RegisterListener", mock.Anything).Return() - or.mti.On("Init", mock.Anything, "token", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - ctx := context.Background() - err := or.initPlugins(ctx) - assert.EqualError(t, err, "pop") -} - func TestInitAllPluginsOK(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) - or.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) or.mdi.On("RegisterListener", mock.Anything).Return() - or.mbi.On("Init", mock.Anything, mock.Anything, or.mmi).Return(nil) or.mbi.On("RegisterListener", mock.Anything).Return() or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return([]*core.Identity{{}}, nil, nil) - or.mdx.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) or.mdx.On("RegisterListener", mock.Anything).Return() - or.mps.On("Init", mock.Anything, mock.Anything).Return(nil) + or.mdx.On("SetNodes", mock.Anything).Return() or.mps.On("RegisterListener", mock.Anything).Return() - or.mti.On("Init", mock.Anything, "token", mock.Anything).Return(nil) or.mti.On("RegisterListener", mock.Anything).Return() err := or.Init(or.ctx, or.cancelCtx) assert.NoError(t, err) @@ -489,28 +415,6 @@ func TestStartStopOk(t *testing.T) { or.WaitStop() // swallows dups } -func TestGetComponents(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - - or.mdi.On("Init", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) - - ctx, cancelCtx := context.WithCancel(context.Background()) - err := or.Init(ctx, cancelCtx) - assert.EqualError(t, err, "pop") - - assert.Equal(t, or.mbm, or.Broadcast()) - assert.Equal(t, or.mpm, or.PrivateMessaging()) - assert.Equal(t, or.mem, or.Events()) - assert.Equal(t, or.mba, or.BatchManager()) - assert.Equal(t, or.mnm, or.NetworkMap()) - assert.Equal(t, or.mdm, or.Data()) - assert.Equal(t, or.mam, or.Assets()) - assert.Equal(t, or.mcm, or.Contracts()) - assert.Equal(t, or.mmi, or.Metrics()) - assert.Equal(t, or.mom, or.Operations()) -} - func TestNetworkAction(t *testing.T) { or := newTestOrchestrator() or.mim.On("NormalizeSigningKey", context.Background(), "ff_system", "", identity.KeyNormalizationBlockchainPlugin).Return("0x123", nil) diff --git a/mocks/dataexchangemocks/plugin.go b/mocks/dataexchangemocks/plugin.go index 4c53d8c4df..0bae603467 100644 --- a/mocks/dataexchangemocks/plugin.go +++ b/mocks/dataexchangemocks/plugin.go @@ -127,13 +127,13 @@ func (_m *Plugin) GetEndpointInfo(ctx context.Context) (fftypes.JSONObject, erro return r0, r1 } -// Init provides a mock function with given fields: ctx, _a1, nodes -func (_m *Plugin) Init(ctx context.Context, _a1 config.Section, nodes []fftypes.JSONObject) error { - ret := _m.Called(ctx, _a1, nodes) +// Init provides a mock function with given fields: ctx, _a1 +func (_m *Plugin) Init(ctx context.Context, _a1 config.Section) error { + ret := _m.Called(ctx, _a1) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, config.Section, []fftypes.JSONObject) error); ok { - r0 = rf(ctx, _a1, nodes) + if rf, ok := ret.Get(0).(func(context.Context, config.Section) error); ok { + r0 = rf(ctx, _a1) } else { r0 = ret.Error(0) } @@ -179,6 +179,11 @@ func (_m *Plugin) SendMessage(ctx context.Context, nsOpID string, peerID string, return r0 } +// SetNodes provides a mock function with given fields: nodes +func (_m *Plugin) SetNodes(nodes []fftypes.JSONObject) { + _m.Called(nodes) +} + // Start provides a mock function with given fields: func (_m *Plugin) Start() error { ret := _m.Called() diff --git a/pkg/dataexchange/plugin.go b/pkg/dataexchange/plugin.go index 88d74df3e1..bdb6e7ff38 100644 --- a/pkg/dataexchange/plugin.go +++ b/pkg/dataexchange/plugin.go @@ -61,7 +61,10 @@ type Plugin interface { InitConfig(config config.Section) // Init initializes the plugin, with configuration - Init(ctx context.Context, config config.Section, nodes []fftypes.JSONObject) error + Init(ctx context.Context, config config.Section) error + + // SetNodes initializes the known nodes from the database + SetNodes(nodes []fftypes.JSONObject) // RegisterListener registers a listener to receive callbacks RegisterListener(callbacks Callbacks) From 15ddcd538b69ec6995c0bc97da7adb8938607ade Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Wed, 8 Jun 2022 21:36:22 -0400 Subject: [PATCH 21/33] Add separate plugin types in namespace manager Signed-off-by: Andrew Richardson --- internal/namespace/manager.go | 263 ++++++++++++--------- internal/namespace/manager_test.go | 25 +- internal/orchestrator/orchestrator.go | 19 +- internal/orchestrator/orchestrator_test.go | 4 +- 4 files changed, 169 insertions(+), 142 deletions(-) diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index 8f294d3010..3214fd7f6d 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -34,7 +34,12 @@ import ( "github.com/hyperledger/firefly/internal/sharedstorage/ssfactory" "github.com/hyperledger/firefly/internal/spievents" "github.com/hyperledger/firefly/internal/tokens/tifactory" + "github.com/hyperledger/firefly/pkg/blockchain" "github.com/hyperledger/firefly/pkg/core" + "github.com/hyperledger/firefly/pkg/database" + "github.com/hyperledger/firefly/pkg/dataexchange" + "github.com/hyperledger/firefly/pkg/identity" + "github.com/hyperledger/firefly/pkg/sharedstorage" "github.com/hyperledger/firefly/pkg/tokens" ) @@ -79,12 +84,12 @@ type namespaceManager struct { namespaces map[string]*namespace pluginNames map[string]bool plugins struct { - blockchain map[string]orchestrator.BlockchainPlugin - identity map[string]orchestrator.IdentityPlugin - database map[string]orchestrator.DatabasePlugin - sharedstorage map[string]orchestrator.SharedStoragePlugin - dataexchange map[string]orchestrator.DataExchangePlugin - tokens map[string]orchestrator.TokensPlugin + blockchain map[string]blockchainPlugin + identity map[string]identityPlugin + database map[string]databasePlugin + sharedstorage map[string]sharedStoragePlugin + dataexchange map[string]dataExchangePlugin + tokens map[string]tokensPlugin } metricsEnabled bool metrics metrics.Manager @@ -92,6 +97,42 @@ type namespaceManager struct { utOrchestrator orchestrator.Orchestrator } +type blockchainPlugin struct { + name string + config config.Section + plugin blockchain.Plugin +} + +type databasePlugin struct { + name string + config config.Section + plugin database.Plugin +} + +type dataExchangePlugin struct { + name string + config config.Section + plugin dataexchange.Plugin +} + +type sharedStoragePlugin struct { + name string + config config.Section + plugin sharedstorage.Plugin +} + +type tokensPlugin struct { + name string + config config.Section + plugin tokens.Plugin +} + +type identityPlugin struct { + name string + config config.Section + plugin identity.Plugin +} + func NewNamespaceManager(withDefaults bool) Manager { nm := &namespaceManager{ namespaces: make(map[string]*namespace), @@ -242,8 +283,8 @@ func (nm *namespaceManager) loadPlugins(ctx context.Context) (err error) { return nil } -func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[string]orchestrator.TokensPlugin, err error) { - plugins = make(map[string]orchestrator.TokensPlugin) +func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[string]tokensPlugin, err error) { + plugins = make(map[string]tokensPlugin) tokensConfigArraySize := tokensConfig.ArraySize() for i := 0; i < tokensConfigArraySize; i++ { @@ -258,13 +299,10 @@ func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[s return nil, err } - plugins[name] = orchestrator.TokensPlugin{ - PluginConfig: orchestrator.PluginConfig{ - Name: name, - PluginType: pluginType, - Config: config.SubSection(pluginType), - }, - Plugin: plugin, + plugins[name] = tokensPlugin{ + name: name, + config: config.SubSection(pluginType), + plugin: plugin, } } @@ -291,13 +329,10 @@ func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[s return nil, err } - plugins[name] = orchestrator.TokensPlugin{ - PluginConfig: orchestrator.PluginConfig{ - Name: name, - PluginType: pluginType, - Config: deprecatedConfig, - }, - Plugin: plugin, + plugins[name] = tokensPlugin{ + name: name, + config: deprecatedConfig, + plugin: plugin, } } } @@ -305,8 +340,8 @@ func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[s return plugins, err } -func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map[string]orchestrator.DatabasePlugin, err error) { - plugins = make(map[string]orchestrator.DatabasePlugin) +func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map[string]databasePlugin, err error) { + plugins = make(map[string]databasePlugin) dbConfigArraySize := databaseConfig.ArraySize() for i := 0; i < dbConfigArraySize; i++ { config := databaseConfig.ArrayEntry(i) @@ -320,13 +355,10 @@ func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map return nil, err } - plugins[name] = orchestrator.DatabasePlugin{ - PluginConfig: orchestrator.PluginConfig{ - Name: name, - PluginType: pluginType, - Config: config.SubSection(pluginType), - }, - Plugin: plugin, + plugins[name] = databasePlugin{ + name: name, + config: config.SubSection(pluginType), + plugin: plugin, } } @@ -338,13 +370,10 @@ func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map return nil, err } name := "database_0" - plugins[name] = orchestrator.DatabasePlugin{ - PluginConfig: orchestrator.PluginConfig{ - Name: name, - PluginType: pluginType, - Config: deprecatedDatabaseConfig.SubSection(pluginType), - }, - Plugin: plugin, + plugins[name] = databasePlugin{ + name: name, + config: deprecatedDatabaseConfig.SubSection(pluginType), + plugin: plugin, } } @@ -371,8 +400,8 @@ func (nm *namespaceManager) validatePluginConfig(ctx context.Context, config con return name, pluginType, nil } -func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins map[string]orchestrator.DataExchangePlugin, err error) { - plugins = make(map[string]orchestrator.DataExchangePlugin) +func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins map[string]dataExchangePlugin, err error) { + plugins = make(map[string]dataExchangePlugin) dxConfigArraySize := dataexchangeConfig.ArraySize() for i := 0; i < dxConfigArraySize; i++ { config := dataexchangeConfig.ArrayEntry(i) @@ -386,13 +415,10 @@ func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins return nil, err } - plugins[name] = orchestrator.DataExchangePlugin{ - PluginConfig: orchestrator.PluginConfig{ - Name: name, - PluginType: pluginType, - Config: config.SubSection(pluginType), - }, - Plugin: plugin, + plugins[name] = dataExchangePlugin{ + name: name, + config: config.SubSection(pluginType), + plugin: plugin, } } @@ -405,21 +431,18 @@ func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins } name := "dataexchange_0" - plugins[name] = orchestrator.DataExchangePlugin{ - PluginConfig: orchestrator.PluginConfig{ - Name: name, - PluginType: pluginType, - Config: deprecatedDataexchangeConfig.SubSection(pluginType), - }, - Plugin: plugin, + plugins[name] = dataExchangePlugin{ + name: name, + config: deprecatedDataexchangeConfig.SubSection(pluginType), + plugin: plugin, } } return plugins, err } -func (nm *namespaceManager) getIdentityPlugins(ctx context.Context) (plugins map[string]orchestrator.IdentityPlugin, err error) { - plugins = make(map[string]orchestrator.IdentityPlugin) +func (nm *namespaceManager) getIdentityPlugins(ctx context.Context) (plugins map[string]identityPlugin, err error) { + plugins = make(map[string]identityPlugin) configSize := identityConfig.ArraySize() for i := 0; i < configSize; i++ { config := identityConfig.ArrayEntry(i) @@ -433,21 +456,18 @@ func (nm *namespaceManager) getIdentityPlugins(ctx context.Context) (plugins map return nil, err } - plugins[name] = orchestrator.IdentityPlugin{ - PluginConfig: orchestrator.PluginConfig{ - Name: name, - PluginType: pluginType, - Config: config.SubSection(pluginType), - }, - Plugin: plugin, + plugins[name] = identityPlugin{ + name: name, + config: config.SubSection(pluginType), + plugin: plugin, } } return plugins, err } -func (nm *namespaceManager) getBlockchainPlugins(ctx context.Context) (plugins map[string]orchestrator.BlockchainPlugin, err error) { - plugins = make(map[string]orchestrator.BlockchainPlugin) +func (nm *namespaceManager) getBlockchainPlugins(ctx context.Context) (plugins map[string]blockchainPlugin, err error) { + plugins = make(map[string]blockchainPlugin) blockchainConfigArraySize := blockchainConfig.ArraySize() for i := 0; i < blockchainConfigArraySize; i++ { config := blockchainConfig.ArrayEntry(i) @@ -461,13 +481,10 @@ func (nm *namespaceManager) getBlockchainPlugins(ctx context.Context) (plugins m return nil, err } - plugins[name] = orchestrator.BlockchainPlugin{ - PluginConfig: orchestrator.PluginConfig{ - Name: name, - PluginType: pluginType, - Config: config.SubSection(pluginType), - }, - Plugin: plugin, + plugins[name] = blockchainPlugin{ + name: name, + config: config.SubSection(pluginType), + plugin: plugin, } } @@ -480,21 +497,18 @@ func (nm *namespaceManager) getBlockchainPlugins(ctx context.Context) (plugins m } name := "blockchain_0" - plugins[name] = orchestrator.BlockchainPlugin{ - PluginConfig: orchestrator.PluginConfig{ - Name: name, - PluginType: pluginType, - Config: deprecatedBlockchainConfig.SubSection(pluginType), - }, - Plugin: plugin, + plugins[name] = blockchainPlugin{ + name: name, + config: deprecatedBlockchainConfig.SubSection(pluginType), + plugin: plugin, } } return plugins, err } -func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugins map[string]orchestrator.SharedStoragePlugin, err error) { - plugins = make(map[string]orchestrator.SharedStoragePlugin) +func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugins map[string]sharedStoragePlugin, err error) { + plugins = make(map[string]sharedStoragePlugin) configSize := sharedstorageConfig.ArraySize() for i := 0; i < configSize; i++ { config := sharedstorageConfig.ArrayEntry(i) @@ -508,13 +522,10 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin return nil, err } - plugins[name] = orchestrator.SharedStoragePlugin{ - PluginConfig: orchestrator.PluginConfig{ - Name: name, - PluginType: pluginType, - Config: config.SubSection(pluginType), - }, - Plugin: plugin, + plugins[name] = sharedStoragePlugin{ + name: name, + config: config.SubSection(pluginType), + plugin: plugin, } } @@ -527,13 +538,10 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin } name := "sharedstorage_0" - plugins[name] = orchestrator.SharedStoragePlugin{ - PluginConfig: orchestrator.PluginConfig{ - Name: name, - PluginType: pluginType, - Config: deprecatedSharedStorageConfig.SubSection(pluginType), - }, - Plugin: plugin, + plugins[name] = sharedStoragePlugin{ + name: name, + config: deprecatedSharedStorageConfig.SubSection(pluginType), + plugin: plugin, } } @@ -541,28 +549,28 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin } func (nm *namespaceManager) initPlugins(ctx context.Context) (err error) { - for _, plugin := range nm.plugins.database { - if err = plugin.Plugin.Init(ctx, plugin.Config); err != nil { + for _, entry := range nm.plugins.database { + if err = entry.plugin.Init(ctx, entry.config); err != nil { return err } } - for _, plugin := range nm.plugins.blockchain { - if err = plugin.Plugin.Init(ctx, plugin.Config, nm.metrics); err != nil { + for _, entry := range nm.plugins.blockchain { + if err = entry.plugin.Init(ctx, entry.config, nm.metrics); err != nil { return err } } - for _, plugin := range nm.plugins.dataexchange { - if err = plugin.Plugin.Init(ctx, plugin.Config); err != nil { + for _, entry := range nm.plugins.dataexchange { + if err = entry.plugin.Init(ctx, entry.config); err != nil { return err } } - for _, plugin := range nm.plugins.sharedstorage { - if err = plugin.Plugin.Init(ctx, plugin.Config); err != nil { + for _, entry := range nm.plugins.sharedstorage { + if err = entry.plugin.Init(ctx, entry.config); err != nil { return err } } - for _, plugin := range nm.plugins.tokens { - if err = plugin.Plugin.Init(ctx, plugin.Name, plugin.Config); err != nil { + for _, entry := range nm.plugins.tokens { + if err = entry.plugin.Init(ctx, entry.name, entry.config); err != nil { return err } } @@ -683,36 +691,54 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s if result.Blockchain.Plugin != nil { return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") } - result.Blockchain = instance + result.Blockchain = orchestrator.BlockchainPlugin{ + Name: instance.name, + Plugin: instance.plugin, + } continue } if instance, ok := nm.plugins.dataexchange[pluginName]; ok { if result.DataExchange.Plugin != nil { return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "dataexchange") } - result.DataExchange = instance + result.DataExchange = orchestrator.DataExchangePlugin{ + Name: instance.name, + Plugin: instance.plugin, + } continue } if instance, ok := nm.plugins.sharedstorage[pluginName]; ok { if result.SharedStorage.Plugin != nil { return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "sharedstorage") } - result.SharedStorage = instance + result.SharedStorage = orchestrator.SharedStoragePlugin{ + Name: instance.name, + Plugin: instance.plugin, + } continue } if instance, ok := nm.plugins.database[pluginName]; ok { if result.Database.Plugin != nil { return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") } - result.Database = instance + result.Database = orchestrator.DatabasePlugin{ + Name: instance.name, + Plugin: instance.plugin, + } continue } if instance, ok := nm.plugins.tokens[pluginName]; ok { - result.Tokens = append(result.Tokens, instance) + result.Tokens = append(result.Tokens, orchestrator.TokensPlugin{ + Name: instance.name, + Plugin: instance.plugin, + }) continue } if instance, ok := nm.plugins.identity[pluginName]; ok { - result.Identity = instance + result.Identity = orchestrator.IdentityPlugin{ + Name: instance.name, + Plugin: instance.plugin, + } continue } @@ -736,7 +762,10 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name stri if result.Blockchain.Plugin != nil { return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") } - result.Blockchain = instance + result.Blockchain = orchestrator.BlockchainPlugin{ + Name: instance.name, + Plugin: instance.plugin, + } continue } if _, ok := nm.plugins.dataexchange[pluginName]; ok { @@ -749,11 +778,17 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name stri if result.Database.Plugin != nil { return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") } - result.Database = instance + result.Database = orchestrator.DatabasePlugin{ + Name: instance.name, + Plugin: instance.plugin, + } continue } if instance, ok := nm.plugins.tokens[pluginName]; ok { - result.Tokens = append(result.Tokens, instance) + result.Tokens = append(result.Tokens, orchestrator.TokensPlugin{ + Name: instance.name, + Plugin: instance.plugin, + }) continue } diff --git a/internal/namespace/manager_test.go b/internal/namespace/manager_test.go index e727aa2161..1226a6697d 100644 --- a/internal/namespace/manager_test.go +++ b/internal/namespace/manager_test.go @@ -29,7 +29,6 @@ import ( "github.com/hyperledger/firefly/internal/database/difactory" "github.com/hyperledger/firefly/internal/dataexchange/dxfactory" "github.com/hyperledger/firefly/internal/identity/iifactory" - "github.com/hyperledger/firefly/internal/orchestrator" "github.com/hyperledger/firefly/internal/sharedstorage/ssfactory" "github.com/hyperledger/firefly/internal/tokens/tifactory" "github.com/hyperledger/firefly/mocks/blockchainmocks" @@ -89,23 +88,23 @@ func newTestNamespaceManager(resetConfig bool) *testNamespaceManager { pluginNames: make(map[string]bool), }, } - nm.plugins.blockchain = map[string]orchestrator.BlockchainPlugin{ - "ethereum": {Plugin: nm.mbi}, + nm.plugins.blockchain = map[string]blockchainPlugin{ + "ethereum": {plugin: nm.mbi}, } - nm.plugins.database = map[string]orchestrator.DatabasePlugin{ - "postgres": {Plugin: nm.mdi}, + nm.plugins.database = map[string]databasePlugin{ + "postgres": {plugin: nm.mdi}, } - nm.plugins.dataexchange = map[string]orchestrator.DataExchangePlugin{ - "ffdx": {Plugin: nm.mdx}, + nm.plugins.dataexchange = map[string]dataExchangePlugin{ + "ffdx": {plugin: nm.mdx}, } - nm.plugins.sharedstorage = map[string]orchestrator.SharedStoragePlugin{ - "ipfs": {Plugin: nm.mps}, + nm.plugins.sharedstorage = map[string]sharedStoragePlugin{ + "ipfs": {plugin: nm.mps}, } - nm.plugins.identity = map[string]orchestrator.IdentityPlugin{ - "tbd": {Plugin: &identitymocks.Plugin{}}, + nm.plugins.identity = map[string]identityPlugin{ + "tbd": {plugin: &identitymocks.Plugin{}}, } - nm.plugins.tokens = map[string]orchestrator.TokensPlugin{ - "erc721": {Plugin: nm.mti}, + nm.plugins.tokens = map[string]tokensPlugin{ + "erc721": {plugin: nm.mti}, } nm.namespaceManager.metrics = nm.mmi nm.namespaceManager.adminEvents = nm.mae diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index e3e8c6448f..a8298f1d0f 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -19,7 +19,6 @@ package orchestrator import ( "context" - "github.com/hyperledger/firefly-common/pkg/config" "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly-common/pkg/i18n" "github.com/hyperledger/firefly/internal/assets" @@ -119,39 +118,33 @@ type Orchestrator interface { SubmitNetworkAction(ctx context.Context, ns string, action *core.NetworkAction) error } -type PluginConfig struct { - Name string - PluginType string - Config config.Section -} - type BlockchainPlugin struct { - PluginConfig + Name string Plugin blockchain.Plugin } type DatabasePlugin struct { - PluginConfig + Name string Plugin database.Plugin } type DataExchangePlugin struct { - PluginConfig + Name string Plugin dataexchange.Plugin } type SharedStoragePlugin struct { - PluginConfig + Name string Plugin sharedstorage.Plugin } type TokensPlugin struct { - PluginConfig + Name string Plugin tokens.Plugin } type IdentityPlugin struct { - PluginConfig + Name string Plugin idplugin.Plugin } diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index e3581bdf1b..7fa087eb46 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -157,8 +157,8 @@ func newTestOrchestrator() *testOrchestrator { tor.orchestrator.plugins.DataExchange.Plugin = tor.mdx tor.orchestrator.plugins.Database.Plugin = tor.mdi tor.orchestrator.plugins.Tokens = []TokensPlugin{{ - PluginConfig: PluginConfig{Name: "token"}, - Plugin: tor.mti, + Name: "token", + Plugin: tor.mti, }} tor.mdi.On("Name").Return("mock-di").Maybe() tor.mem.On("Name").Return("mock-ei").Maybe() From de9ad8679e586230dd97457936e858fa96b5bb2f Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Thu, 9 Jun 2022 11:25:25 -0400 Subject: [PATCH 22/33] Blockchain plugin can track multiple listeners Each listener will ignore events outside its namespace. Signed-off-by: Andrew Richardson --- internal/blockchain/ethereum/ethereum.go | 43 +++++++++++- internal/blockchain/ethereum/ethereum_test.go | 66 +++++++------------ internal/blockchain/fabric/fabric.go | 43 +++++++++++- internal/blockchain/fabric/fabric_test.go | 53 +++++++++------ internal/events/batch_pin_complete.go | 5 +- internal/events/blockchain_event.go | 4 ++ internal/events/blockchain_event_test.go | 20 +++--- internal/events/network_action.go | 4 +- internal/operations/manager.go | 18 ++--- internal/operations/manager_test.go | 4 +- internal/operations/operation_updater.go | 6 +- internal/operations/operation_updater_test.go | 5 +- internal/orchestrator/orchestrator.go | 12 ++-- .../shareddownload/download_manager_test.go | 2 +- pkg/blockchain/plugin.go | 2 +- 15 files changed, 186 insertions(+), 101 deletions(-) diff --git a/internal/blockchain/ethereum/ethereum.go b/internal/blockchain/ethereum/ethereum.go index 340ace0d83..2646a66f0f 100644 --- a/internal/blockchain/ethereum/ethereum.go +++ b/internal/blockchain/ethereum/ethereum.go @@ -55,7 +55,7 @@ type Ethereum struct { prefixShort string prefixLong string capabilities *blockchain.Capabilities - callbacks blockchain.Callbacks + callbacks callbacks client *resty.Client fftmClient *resty.Client streams *streamManager @@ -76,6 +76,43 @@ type Ethereum struct { contractConfSize int } +type callbacks struct { + listeners []blockchain.Callbacks +} + +func (cb *callbacks) BlockchainOpUpdate(plugin blockchain.Plugin, nsOpID string, txState blockchain.TransactionStatus, blockchainTXID, errorMessage string, opOutput fftypes.JSONObject) { + for _, cb := range cb.listeners { + cb.BlockchainOpUpdate(plugin, nsOpID, txState, blockchainTXID, errorMessage, opOutput) + } +} + +func (cb *callbacks) BatchPinComplete(batch *blockchain.BatchPin, signingKey *core.VerifierRef) error { + for _, cb := range cb.listeners { + if err := cb.BatchPinComplete(batch, signingKey); err != nil { + return err + } + } + return nil +} + +func (cb *callbacks) BlockchainNetworkAction(action string, event *blockchain.Event, signingKey *core.VerifierRef) error { + for _, cb := range cb.listeners { + if err := cb.BlockchainNetworkAction(action, event, signingKey); err != nil { + return err + } + } + return nil +} + +func (cb *callbacks) BlockchainEvent(event *blockchain.EventWithSubscription) error { + for _, cb := range cb.listeners { + if err := cb.BlockchainEvent(event); err != nil { + return err + } + } + return nil +} + type eventStreamWebsocket struct { Topic string `json:"topic"` } @@ -213,8 +250,8 @@ func (e *Ethereum) Init(ctx context.Context, config config.Section, metrics metr return nil } -func (e *Ethereum) RegisterListener(callbacks blockchain.Callbacks) { - e.callbacks = callbacks +func (e *Ethereum) RegisterListener(listener blockchain.Callbacks) { + e.callbacks.listeners = append(e.callbacks.listeners, listener) } func (e *Ethereum) Start() (err error) { diff --git a/internal/blockchain/ethereum/ethereum_test.go b/internal/blockchain/ethereum/ethereum_test.go index 0a1a06c60b..5196f0bffd 100644 --- a/internal/blockchain/ethereum/ethereum_test.go +++ b/internal/blockchain/ethereum/ethereum_test.go @@ -75,7 +75,6 @@ func resetConf(e *Ethereum) { func newTestEthereum() (*Ethereum, func()) { ctx, cancel := context.WithCancel(context.Background()) - em := &blockchainmocks.Callbacks{} wsm := &wsmocks.WSClient{} mm := &metricsmocks.Manager{} mm.On("IsMetricsEnabled").Return(true) @@ -87,7 +86,6 @@ func newTestEthereum() (*Ethereum, func()) { topic: "topic1", prefixShort: defaultPrefixShort, prefixLong: defaultPrefixLong, - callbacks: em, wsconn: wsm, metrics: mm, } @@ -1095,7 +1093,7 @@ func TestHandleMessageBatchPinOK(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Ethereum{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" e.fireflyContract.networkVersion = 1 @@ -1179,10 +1177,7 @@ func TestHandleMessageBatchPinMissingAuthor(t *testing.T) { } ]`) - em := &blockchainmocks.Callbacks{} - e := &Ethereum{ - callbacks: em, - } + e := &Ethereum{} e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" var events []interface{} @@ -1191,8 +1186,6 @@ func TestHandleMessageBatchPinMissingAuthor(t *testing.T) { err = e.handleMessageBatch(context.Background(), events) assert.NoError(t, err) - em.AssertExpectations(t) - } func TestHandleMessageEmptyPayloadRef(t *testing.T) { @@ -1223,7 +1216,7 @@ func TestHandleMessageEmptyPayloadRef(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Ethereum{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" e.fireflyContract.networkVersion = 1 @@ -1285,7 +1278,7 @@ func TestHandleMessageBatchPinExit(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Ethereum{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" e.fireflyContract.networkVersion = 1 @@ -1298,11 +1291,11 @@ func TestHandleMessageBatchPinExit(t *testing.T) { err = e.handleMessageBatch(context.Background(), events) assert.EqualError(t, err, "pop") + em.AssertExpectations(t) } func TestHandleMessageBatchPinEmpty(t *testing.T) { - em := &blockchainmocks.Callbacks{} - e := &Ethereum{callbacks: em} + e := &Ethereum{} e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" var events []interface{} @@ -1316,12 +1309,10 @@ func TestHandleMessageBatchPinEmpty(t *testing.T) { assert.NoError(t, err) err = e.handleMessageBatch(context.Background(), events) assert.NoError(t, err) - assert.Equal(t, 0, len(em.Calls)) } func TestHandleMessageBatchMissingData(t *testing.T) { - em := &blockchainmocks.Callbacks{} - e := &Ethereum{callbacks: em} + e := &Ethereum{} e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" var events []interface{} @@ -1336,12 +1327,10 @@ func TestHandleMessageBatchMissingData(t *testing.T) { assert.NoError(t, err) err = e.handleMessageBatch(context.Background(), events) assert.NoError(t, err) - assert.Equal(t, 0, len(em.Calls)) } func TestHandleMessageBatchPinBadTransactionID(t *testing.T) { - em := &blockchainmocks.Callbacks{} - e := &Ethereum{callbacks: em} + e := &Ethereum{} e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" data := fftypes.JSONAnyPtr(`[{ "address": "0x1C197604587F046FD40684A8f21f4609FB811A7b", @@ -1368,12 +1357,10 @@ func TestHandleMessageBatchPinBadTransactionID(t *testing.T) { assert.NoError(t, err) err = e.handleMessageBatch(context.Background(), events) assert.NoError(t, err) - assert.Equal(t, 0, len(em.Calls)) } func TestHandleMessageBatchPinBadIDentity(t *testing.T) { - em := &blockchainmocks.Callbacks{} - e := &Ethereum{callbacks: em} + e := &Ethereum{} e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" data := fftypes.JSONAnyPtr(`[{ "address": "0x1C197604587F046FD40684A8f21f4609FB811A7b", @@ -1400,12 +1387,10 @@ func TestHandleMessageBatchPinBadIDentity(t *testing.T) { assert.NoError(t, err) err = e.handleMessageBatch(context.Background(), events) assert.NoError(t, err) - assert.Equal(t, 0, len(em.Calls)) } func TestHandleMessageBatchPinBadBatchHash(t *testing.T) { - em := &blockchainmocks.Callbacks{} - e := &Ethereum{callbacks: em} + e := &Ethereum{} e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" data := fftypes.JSONAnyPtr(`[{ "address": "0x1C197604587F046FD40684A8f21f4609FB811A7b", @@ -1432,12 +1417,10 @@ func TestHandleMessageBatchPinBadBatchHash(t *testing.T) { assert.NoError(t, err) err = e.handleMessageBatch(context.Background(), events) assert.NoError(t, err) - assert.Equal(t, 0, len(em.Calls)) } func TestHandleMessageBatchPinBadPin(t *testing.T) { - em := &blockchainmocks.Callbacks{} - e := &Ethereum{callbacks: em} + e := &Ethereum{} e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" data := fftypes.JSONAnyPtr(`[{ "address": "0x1C197604587F046FD40684A8f21f4609FB811A7b", @@ -1464,15 +1447,12 @@ func TestHandleMessageBatchPinBadPin(t *testing.T) { assert.NoError(t, err) err = e.handleMessageBatch(context.Background(), events) assert.NoError(t, err) - assert.Equal(t, 0, len(em.Calls)) } func TestHandleMessageBatchBadJSON(t *testing.T) { - em := &blockchainmocks.Callbacks{} - e := &Ethereum{callbacks: em} + e := &Ethereum{} err := e.handleMessageBatch(context.Background(), []interface{}{10, 20}) assert.NoError(t, err) - assert.Equal(t, 0, len(em.Calls)) } func TestEventLoopContextCancelled(t *testing.T) { @@ -1523,7 +1503,7 @@ func TestHandleReceiptTXSuccess(t *testing.T) { e := &Ethereum{ ctx: context.Background(), topic: "topic1", - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, wsconn: wsm, } @@ -1564,6 +1544,7 @@ func TestHandleReceiptTXSuccess(t *testing.T) { assert.NoError(t, err) e.handleReceipt(context.Background(), reply) + em.AssertExpectations(t) } func TestHandleBadPayloadsAndThenReceiptFailure(t *testing.T) { @@ -1591,7 +1572,8 @@ func TestHandleBadPayloadsAndThenReceiptFailure(t *testing.T) { "requestPayload": "{\"from\":\"0x91d2b4381a4cd5c7c0f27565a7d4b829844c8635\",\"gas\":0,\"gasPrice\":0,\"headers\":{\"id\":\"6fb94fff-81d3-4094-567d-e031b1871694\",\"type\":\"SendTransaction\"},\"method\":{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"txnId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"batchId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"payloadRef\",\"type\":\"bytes32\"}],\"name\":\"broadcastBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},\"params\":[\"12345\",\"!\",\"!\"],\"to\":\"0xd3266a857285fb75eb7df37353b4a15c8bb828f5\",\"value\":0}" }`) - em := e.callbacks.(*blockchainmocks.Callbacks) + em := &blockchainmocks.Callbacks{} + e.callbacks.listeners = []blockchain.Callbacks{em} txsu := em.On("BlockchainOpUpdate", e, "ns1:"+operationID.String(), @@ -1609,16 +1591,16 @@ func TestHandleBadPayloadsAndThenReceiptFailure(t *testing.T) { r <- []byte(`"not an object"`) // ignored wrong type r <- data.Bytes() <-done + + em.AssertExpectations(t) } func TestHandleMsgBatchBadData(t *testing.T) { - em := &blockchainmocks.Callbacks{} wsm := &wsmocks.WSClient{} e := &Ethereum{ - ctx: context.Background(), - topic: "topic1", - callbacks: em, - wsconn: wsm, + ctx: context.Background(), + topic: "topic1", + wsconn: wsm, } var reply fftypes.JSONObject @@ -1836,7 +1818,7 @@ func TestHandleMessageContractEvent(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Ethereum{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" @@ -1898,7 +1880,7 @@ func TestHandleMessageContractEventError(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Ethereum{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" @@ -2980,7 +2962,7 @@ func TestHandleNetworkAction(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Ethereum{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" diff --git a/internal/blockchain/fabric/fabric.go b/internal/blockchain/fabric/fabric.go index 33547deecb..efea17ce18 100644 --- a/internal/blockchain/fabric/fabric.go +++ b/internal/blockchain/fabric/fabric.go @@ -51,7 +51,7 @@ type Fabric struct { prefixShort string prefixLong string capabilities *blockchain.Capabilities - callbacks blockchain.Callbacks + callbacks callbacks client *resty.Client streams *streamManager streamID string @@ -71,6 +71,43 @@ type Fabric struct { contractConfSize int } +type callbacks struct { + listeners []blockchain.Callbacks +} + +func (cb *callbacks) BlockchainOpUpdate(plugin blockchain.Plugin, nsOpID string, txState blockchain.TransactionStatus, blockchainTXID, errorMessage string, opOutput fftypes.JSONObject) { + for _, cb := range cb.listeners { + cb.BlockchainOpUpdate(plugin, nsOpID, txState, blockchainTXID, errorMessage, opOutput) + } +} + +func (cb *callbacks) BatchPinComplete(batch *blockchain.BatchPin, signingKey *core.VerifierRef) error { + for _, cb := range cb.listeners { + if err := cb.BatchPinComplete(batch, signingKey); err != nil { + return err + } + } + return nil +} + +func (cb *callbacks) BlockchainNetworkAction(action string, event *blockchain.Event, signingKey *core.VerifierRef) error { + for _, cb := range cb.listeners { + if err := cb.BlockchainNetworkAction(action, event, signingKey); err != nil { + return err + } + } + return nil +} + +func (cb *callbacks) BlockchainEvent(event *blockchain.EventWithSubscription) error { + for _, cb := range cb.listeners { + if err := cb.BlockchainEvent(event); err != nil { + return err + } + } + return nil +} + type eventStreamWebsocket struct { Topic string `json:"topic"` } @@ -285,8 +322,8 @@ func (f *Fabric) TerminateContract(ctx context.Context, contracts *core.FireFlyC return f.ConfigureContract(ctx, contracts) } -func (f *Fabric) RegisterListener(callbacks blockchain.Callbacks) { - f.callbacks = callbacks +func (f *Fabric) RegisterListener(listener blockchain.Callbacks) { + f.callbacks.listeners = append(f.callbacks.listeners, listener) } func (f *Fabric) Start() (err error) { diff --git a/internal/blockchain/fabric/fabric_test.go b/internal/blockchain/fabric/fabric_test.go index 4cb08d01a0..110df20803 100644 --- a/internal/blockchain/fabric/fabric_test.go +++ b/internal/blockchain/fabric/fabric_test.go @@ -53,7 +53,6 @@ func resetConf(e *Fabric) { func newTestFabric() (*Fabric, func()) { ctx, cancel := context.WithCancel(context.Background()) - em := &blockchainmocks.Callbacks{} wsm := &wsmocks.WSClient{} e := &Fabric{ ctx: ctx, @@ -62,7 +61,6 @@ func newTestFabric() (*Fabric, func()) { topic: "topic1", prefixShort: defaultPrefixShort, prefixLong: defaultPrefixLong, - callbacks: em, wsconn: wsm, } e.fireflyContract.chaincode = "firefly" @@ -945,7 +943,7 @@ func TestHandleMessageBatchPinOK(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Fabric{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-0910f6a8-7bd6-4ced-453e-2db68149ce8e" @@ -992,7 +990,7 @@ func TestHandleMessageEmptyPayloadRef(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Fabric{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-0910f6a8-7bd6-4ced-453e-2db68149ce8e" @@ -1039,7 +1037,7 @@ func TestHandleMessageBatchPinExit(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Fabric{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-0910f6a8-7bd6-4ced-453e-2db68149ce8e" @@ -1071,7 +1069,9 @@ func TestHandleMessageBatchPinEmpty(t *testing.T) { ]`) em := &blockchainmocks.Callbacks{} - e := &Fabric{callbacks: em} + e := &Fabric{ + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, + } e.fireflyContract.subscription = "sb-0910f6a8-7bd6-4ced-453e-2db68149ce8e" var events []interface{} @@ -1095,7 +1095,9 @@ func TestHandleMessageUnknownEventName(t *testing.T) { ]`) em := &blockchainmocks.Callbacks{} - e := &Fabric{callbacks: em} + e := &Fabric{ + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, + } e.fireflyContract.subscription = "sb-0910f6a8-7bd6-4ced-453e-2db68149ce8e" var events []interface{} @@ -1108,7 +1110,9 @@ func TestHandleMessageUnknownEventName(t *testing.T) { func TestHandleMessageBatchPinBadBatchHash(t *testing.T) { em := &blockchainmocks.Callbacks{} - e := &Fabric{callbacks: em} + e := &Fabric{ + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, + } e.fireflyContract.subscription = "sb-0910f6a8-7bd6-4ced-453e-2db68149ce8e" data := []byte(`[{ "chaincodeId": "firefly", @@ -1128,7 +1132,9 @@ func TestHandleMessageBatchPinBadBatchHash(t *testing.T) { func TestHandleMessageBatchPinBadPin(t *testing.T) { em := &blockchainmocks.Callbacks{} - e := &Fabric{callbacks: em} + e := &Fabric{ + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, + } e.fireflyContract.subscription = "sb-0910f6a8-7bd6-4ced-453e-2db68149ce8e" data := []byte(`[{ "chaincodeId": "firefly", @@ -1148,7 +1154,9 @@ func TestHandleMessageBatchPinBadPin(t *testing.T) { func TestHandleMessageBatchPinBadPayloadEncoding(t *testing.T) { em := &blockchainmocks.Callbacks{} - e := &Fabric{callbacks: em} + e := &Fabric{ + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, + } e.fireflyContract.subscription = "sb-0910f6a8-7bd6-4ced-453e-2db68149ce8e" data := []byte(`[{ "chaincodeId": "firefly", @@ -1168,7 +1176,9 @@ func TestHandleMessageBatchPinBadPayloadEncoding(t *testing.T) { func TestHandleMessageBatchPinBadPayloadUUIDs(t *testing.T) { em := &blockchainmocks.Callbacks{} - e := &Fabric{callbacks: em} + e := &Fabric{ + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, + } e.fireflyContract.subscription = "sb-0910f6a8-7bd6-4ced-453e-2db68149ce8e" data := []byte(`[{ "chaincodeId": "firefly", @@ -1188,7 +1198,9 @@ func TestHandleMessageBatchPinBadPayloadUUIDs(t *testing.T) { func TestHandleMessageBatchBadJSON(t *testing.T) { em := &blockchainmocks.Callbacks{} - e := &Fabric{callbacks: em} + e := &Fabric{ + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, + } err := e.handleMessageBatch(context.Background(), []interface{}{10, 20}) assert.NoError(t, err) assert.Equal(t, 0, len(em.Calls)) @@ -1257,7 +1269,8 @@ func TestEventLoopUnexpectedMessage(t *testing.T) { "receivedAt": 1622428511616, "requestPayload": "{\"from\":\"0x91d2b4381a4cd5c7c0f27565a7d4b829844c8635\",\"gas\":0,\"gasPrice\":0,\"headers\":{\"id\":\"6fb94fff-81d3-4094-567d-e031b1871694\",\"type\":\"SendTransaction\"},\"method\":{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"txnId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"batchId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"payloadRef\",\"type\":\"bytes32\"}],\"name\":\"broadcastBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},\"params\":[\"12345\",\"!\",\"!\"],\"to\":\"0xd3266a857285fb75eb7df37353b4a15c8bb828f5\",\"value\":0}" }`) - em := e.callbacks.(*blockchainmocks.Callbacks) + em := &blockchainmocks.Callbacks{} + e.RegisterListener(em) txsu := em.On("BlockchainOpUpdate", e, "ns1:"+operationID.String(), @@ -1283,7 +1296,7 @@ func TestHandleReceiptTXSuccess(t *testing.T) { e := &Fabric{ ctx: context.Background(), topic: "topic1", - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, wsconn: wsm, } @@ -1323,7 +1336,7 @@ func TestHandleReceiptNoRequestID(t *testing.T) { e := &Fabric{ ctx: context.Background(), topic: "topic1", - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, wsconn: wsm, } @@ -1340,7 +1353,7 @@ func TestHandleReceiptFailedTx(t *testing.T) { e := &Fabric{ ctx: context.Background(), topic: "topic1", - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, wsconn: wsm, } @@ -1532,7 +1545,7 @@ func TestHandleMessageContractEvent(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Fabric{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" @@ -1590,7 +1603,7 @@ func TestHandleMessageContractEventBadPayload(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Fabric{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" @@ -1618,7 +1631,7 @@ func TestHandleMessageContractEventError(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Fabric{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" @@ -2017,7 +2030,7 @@ func TestHandleNetworkAction(t *testing.T) { em := &blockchainmocks.Callbacks{} e := &Fabric{ - callbacks: em, + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, } e.fireflyContract.subscription = "sb-0910f6a8-7bd6-4ced-453e-2db68149ce8e" diff --git a/internal/events/batch_pin_complete.go b/internal/events/batch_pin_complete.go index 799722ec7c..f8e7982c61 100644 --- a/internal/events/batch_pin_complete.go +++ b/internal/events/batch_pin_complete.go @@ -32,11 +32,14 @@ import ( // We must block here long enough to get the payload from the sharedstorage, persist the messages in the correct // sequence, and also persist all the data. func (em *eventManager) BatchPinComplete(bi blockchain.Plugin, batchPin *blockchain.BatchPin, signingKey *core.VerifierRef) error { + if batchPin.Namespace != em.namespace { + log.L(em.ctx).Debugf("Ignoring BatchPin from wrong namespace '%s'", batchPin.Namespace) + return nil // move on + } if batchPin.TransactionID == nil { log.L(em.ctx).Errorf("Invalid BatchPin transaction - ID is nil") return nil // move on } - if err := core.ValidateFFNameField(em.ctx, batchPin.Namespace, "namespace"); err != nil { log.L(em.ctx).Errorf("Invalid transaction ID='%s' - invalid namespace '%s': %a", batchPin.TransactionID, batchPin.Namespace, err) return nil // move on diff --git a/internal/events/blockchain_event.go b/internal/events/blockchain_event.go index 561a66ba61..4cee6ae4f6 100644 --- a/internal/events/blockchain_event.go +++ b/internal/events/blockchain_event.go @@ -127,6 +127,10 @@ func (em *eventManager) BlockchainEvent(event *blockchain.EventWithSubscription) log.L(ctx).Warnf("Event received from unknown subscription %s", event.Subscription) return nil // no retry } + if sub.Namespace != em.namespace { + log.L(em.ctx).Debugf("Ignoring blockchain event from wrong namespace '%s'", sub.Namespace) + return nil + } chainEvent := buildBlockchainEvent(sub.Namespace, sub.ID, &event.Event, &core.BlockchainTransactionRef{ BlockchainID: event.BlockchainTXID, diff --git a/internal/events/blockchain_event_test.go b/internal/events/blockchain_event_test.go index 64d451befd..5c1ec86b9d 100644 --- a/internal/events/blockchain_event_test.go +++ b/internal/events/blockchain_event_test.go @@ -49,7 +49,7 @@ func TestContractEventWithRetries(t *testing.T) { }, } sub := &core.ContractListener{ - Namespace: "ns", + Namespace: "ns1", ID: fftypes.NewUUID(), Topic: "topic1", } @@ -59,11 +59,11 @@ func TestContractEventWithRetries(t *testing.T) { mdi.On("GetContractListenerByBackendID", mock.Anything, "sb-1").Return(nil, fmt.Errorf("pop")).Once() mdi.On("GetContractListenerByBackendID", mock.Anything, "sb-1").Return(sub, nil).Times(1) // cached mth := em.txHelper.(*txcommonmocks.Helper) - mdi.On("GetBlockchainEventByProtocolID", mock.Anything, "ns", sub.ID, ev.ProtocolID).Return(nil, nil) + mdi.On("GetBlockchainEventByProtocolID", mock.Anything, "ns1", sub.ID, ev.ProtocolID).Return(nil, nil) mth.On("InsertBlockchainEvent", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")).Once() mth.On("InsertBlockchainEvent", mock.Anything, mock.MatchedBy(func(e *core.BlockchainEvent) bool { eventID = e.ID - return *e.Listener == *sub.ID && e.Name == "Changed" && e.Namespace == "ns" + return *e.Listener == *sub.ID && e.Name == "Changed" && e.Namespace == "ns1" })).Return(nil).Times(2) mdi.On("GetContractListenerByID", mock.Anything, sub.ID).Return(sub, nil) mdi.On("InsertEvent", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")).Once() @@ -111,7 +111,7 @@ func TestPersistBlockchainEventDuplicate(t *testing.T) { ev := &core.BlockchainEvent{ Name: "Changed", - Namespace: "ns", + Namespace: "ns1", ProtocolID: "10/20/30", Output: fftypes.JSONObject{ "value": "1", @@ -123,7 +123,7 @@ func TestPersistBlockchainEventDuplicate(t *testing.T) { } mdi := em.database.(*databasemocks.Plugin) - mdi.On("GetBlockchainEventByProtocolID", mock.Anything, "ns", ev.Listener, ev.ProtocolID).Return(&core.BlockchainEvent{}, nil) + mdi.On("GetBlockchainEventByProtocolID", mock.Anything, "ns1", ev.Listener, ev.ProtocolID).Return(&core.BlockchainEvent{}, nil) err := em.maybePersistBlockchainEvent(em.ctx, ev) assert.NoError(t, err) @@ -137,7 +137,7 @@ func TestPersistBlockchainEventLookupFail(t *testing.T) { ev := &core.BlockchainEvent{ Name: "Changed", - Namespace: "ns", + Namespace: "ns1", ProtocolID: "10/20/30", Output: fftypes.JSONObject{ "value": "1", @@ -149,7 +149,7 @@ func TestPersistBlockchainEventLookupFail(t *testing.T) { } mdi := em.database.(*databasemocks.Plugin) - mdi.On("GetBlockchainEventByProtocolID", mock.Anything, "ns", ev.Listener, ev.ProtocolID).Return(nil, fmt.Errorf("pop")) + mdi.On("GetBlockchainEventByProtocolID", mock.Anything, "ns1", ev.Listener, ev.ProtocolID).Return(nil, fmt.Errorf("pop")) err := em.maybePersistBlockchainEvent(em.ctx, ev) assert.EqualError(t, err, "pop") @@ -163,7 +163,7 @@ func TestPersistBlockchainEventChainListenerLookupFail(t *testing.T) { ev := &core.BlockchainEvent{ Name: "Changed", - Namespace: "ns", + Namespace: "ns1", ProtocolID: "10/20/30", Output: fftypes.JSONObject{ "value": "1", @@ -176,7 +176,7 @@ func TestPersistBlockchainEventChainListenerLookupFail(t *testing.T) { mdi := em.database.(*databasemocks.Plugin) mth := em.txHelper.(*txcommonmocks.Helper) - mdi.On("GetBlockchainEventByProtocolID", mock.Anything, "ns", ev.Listener, ev.ProtocolID).Return(nil, nil) + mdi.On("GetBlockchainEventByProtocolID", mock.Anything, "ns1", ev.Listener, ev.ProtocolID).Return(nil, nil) mth.On("InsertBlockchainEvent", mock.Anything, mock.Anything).Return(nil) mdi.On("GetContractListenerByID", mock.Anything, ev.Listener).Return(nil, fmt.Errorf("pop")) @@ -192,7 +192,7 @@ func TestGetTopicForChainListenerFallback(t *testing.T) { defer cancel() sub := &core.ContractListener{ - Namespace: "ns", + Namespace: "ns1", ID: fftypes.NewUUID(), Topic: "", } diff --git a/internal/events/network_action.go b/internal/events/network_action.go index 537e94a645..d3fe860d0a 100644 --- a/internal/events/network_action.go +++ b/internal/events/network_action.go @@ -29,13 +29,11 @@ func (em *eventManager) actionTerminate(bi blockchain.Plugin, event *blockchain. if err != nil { return err } - contracts := &namespace.Contracts - if err := bi.TerminateContract(em.ctx, contracts, event); err != nil { + if err := bi.TerminateContract(em.ctx, &namespace.Contracts, event); err != nil { return err } // Currently, a termination event is implied to apply to ALL namespaces return em.database.RunAsGroup(em.ctx, func(ctx context.Context) error { - namespace.Contracts = *contracts if err := em.database.UpsertNamespace(em.ctx, namespace, true); err != nil { return err } diff --git a/internal/operations/manager.go b/internal/operations/manager.go index c5bde77b88..cfbf38501d 100644 --- a/internal/operations/manager.go +++ b/internal/operations/manager.go @@ -57,20 +57,22 @@ const ( ) type operationsManager struct { - ctx context.Context - database database.Plugin - handlers map[core.OpType]OperationHandler - updater *operationUpdater + ctx context.Context + namespace string + database database.Plugin + handlers map[core.OpType]OperationHandler + updater *operationUpdater } -func NewOperationsManager(ctx context.Context, di database.Plugin, txHelper txcommon.Helper) (Manager, error) { +func NewOperationsManager(ctx context.Context, ns string, di database.Plugin, txHelper txcommon.Helper) (Manager, error) { if di == nil || txHelper == nil { return nil, i18n.NewError(ctx, coremsgs.MsgInitializationNilDepError, "OperationsManager") } om := &operationsManager{ - ctx: ctx, - database: di, - handlers: make(map[core.OpType]OperationHandler), + ctx: ctx, + namespace: ns, + database: di, + handlers: make(map[core.OpType]OperationHandler), } updater := newOperationUpdater(ctx, om, di, txHelper) om.updater = updater diff --git a/internal/operations/manager_test.go b/internal/operations/manager_test.go index cf369fb7a7..70da40e9a9 100644 --- a/internal/operations/manager_test.go +++ b/internal/operations/manager_test.go @@ -77,13 +77,13 @@ func newTestOperations(t *testing.T) (*operationsManager, func()) { } ctx, cancel := context.WithCancel(context.Background()) - om, err := NewOperationsManager(ctx, mdi, txHelper) + om, err := NewOperationsManager(ctx, "ns1", mdi, txHelper) assert.NoError(t, err) return om.(*operationsManager), cancel } func TestInitFail(t *testing.T) { - _, err := NewOperationsManager(context.Background(), nil, nil) + _, err := NewOperationsManager(context.Background(), "ns1", nil, nil) assert.Regexp(t, "FF10128", err) } diff --git a/internal/operations/operation_updater.go b/internal/operations/operation_updater.go index 6007773acd..4fea4cca29 100644 --- a/internal/operations/operation_updater.go +++ b/internal/operations/operation_updater.go @@ -107,11 +107,15 @@ func (ou *operationUpdater) pickWorker(ctx context.Context, id *fftypes.UUID, up } func (ou *operationUpdater) SubmitOperationUpdate(ctx context.Context, update *OperationUpdate) { - _, id, err := core.ParseNamespacedOpID(ctx, update.NamespacedOpID) + ns, id, err := core.ParseNamespacedOpID(ctx, update.NamespacedOpID) if err != nil { log.L(ctx).Warnf("Unable to update operation '%s' due to invalid ID: %s", update.NamespacedOpID, err) return } + if ns != ou.manager.namespace { + log.L(ou.ctx).Debugf("Ignoring operation update from wrong namespace '%s'", ns) + return + } if ou.conf.workerCount > 0 { select { diff --git a/internal/operations/operation_updater_test.go b/internal/operations/operation_updater_test.go index 0b2dbddb51..d99e2c5a9e 100644 --- a/internal/operations/operation_updater_test.go +++ b/internal/operations/operation_updater_test.go @@ -55,7 +55,10 @@ func newTestOperationUpdaterCommon(t *testing.T, dbCapabilities *database.Capabi config.Set(coreconfig.OpUpdateWorkerBatchMaxInserts, 200) logrus.SetLevel(logrus.DebugLevel) - mom := &operationsManager{handlers: make(map[fftypes.FFEnum]OperationHandler)} + mom := &operationsManager{ + namespace: "ns1", + handlers: make(map[fftypes.FFEnum]OperationHandler), + } mdi := &databasemocks.Plugin{} mdi.On("Capabilities").Return(dbCapabilities) mdm := &datamocks.Manager{} diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index a8298f1d0f..c1acfa086e 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -21,6 +21,7 @@ import ( "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly-common/pkg/i18n" + "github.com/hyperledger/firefly-common/pkg/log" "github.com/hyperledger/firefly/internal/assets" "github.com/hyperledger/firefly/internal/batch" "github.com/hyperledger/firefly/internal/batchpin" @@ -196,21 +197,22 @@ type orchestrator struct { } func NewOrchestrator(ns string, config Config, plugins Plugins, metrics metrics.Manager, adminEvents spievents.Manager) Orchestrator { - return &orchestrator{ + or := &orchestrator{ namespace: ns, config: config, plugins: plugins, metrics: metrics, adminEvents: adminEvents, } + return or } func (or *orchestrator) Init(ctx context.Context, cancelCtx context.CancelFunc) (err error) { - or.ctx = ctx + or.ctx = log.WithLogField(ctx, "ns", or.namespace) or.cancelCtx = cancelCtx - err = or.initPlugins(ctx) + err = or.initPlugins(or.ctx) if err == nil { - err = or.initComponents(ctx) + err = or.initComponents(or.ctx) } // Bind together the blockchain interface callbacks, with the events manager or.bc.bi = or.plugins.Blockchain.Plugin @@ -414,7 +416,7 @@ func (or *orchestrator) initComponents(ctx context.Context) (err error) { } if or.operations == nil { - if or.operations, err = operations.NewOperationsManager(ctx, or.database(), or.txHelper); err != nil { + if or.operations, err = operations.NewOperationsManager(ctx, or.namespace, or.database(), or.txHelper); err != nil { return err } } diff --git a/internal/shareddownload/download_manager_test.go b/internal/shareddownload/download_manager_test.go index ff77abae25..5e8a1ddcc4 100644 --- a/internal/shareddownload/download_manager_test.go +++ b/internal/shareddownload/download_manager_test.go @@ -54,7 +54,7 @@ func newTestDownloadManager(t *testing.T) (*downloadManager, func()) { mdi.On("Capabilities").Return(&database.Capabilities{ Concurrency: false, }) - operations, err := operations.NewOperationsManager(context.Background(), mdi, txHelper) + operations, err := operations.NewOperationsManager(context.Background(), "ns1", mdi, txHelper) assert.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) diff --git a/pkg/blockchain/plugin.go b/pkg/blockchain/plugin.go index 219e48766f..4ae497d9bb 100644 --- a/pkg/blockchain/plugin.go +++ b/pkg/blockchain/plugin.go @@ -36,7 +36,7 @@ type Plugin interface { Init(ctx context.Context, config config.Section, metrics metrics.Manager) error // RegisterListener registers a listener to receive callbacks - RegisterListener(callbacks Callbacks) + RegisterListener(listener Callbacks) // ConfigureContract initializes the subscription to the FireFly contract // - Checks the provided contract info against the plugin's configuration, and updates it as needed From 492193abe3f42016edc596f9f3a2ed742ff264ad Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Thu, 9 Jun 2022 11:48:43 -0400 Subject: [PATCH 23/33] Data Exchange plugin can track multiple listeners Each listener will ignore events outside its namespace. Signed-off-by: Andrew Richardson --- internal/dataexchange/ffdx/dxevent.go | 4 ++++ internal/dataexchange/ffdx/ffdx.go | 16 +++++++++++++--- internal/dataexchange/ffdx/ffdx_test.go | 10 +++++----- internal/events/dx_callbacks.go | 10 +++++++++- internal/events/dx_callbacks_test.go | 3 +++ internal/identity/tbd/tbd.go | 4 +--- internal/sharedstorage/ipfs/ipfs.go | 4 +--- mocks/blockchainmocks/plugin.go | 6 +++--- mocks/dataexchangemocks/plugin.go | 6 +++--- mocks/identitymocks/plugin.go | 6 +++--- mocks/sharedstoragemocks/plugin.go | 6 +++--- pkg/dataexchange/plugin.go | 3 ++- pkg/identity/plugin.go | 2 +- pkg/sharedstorage/plugin.go | 2 +- 14 files changed, 52 insertions(+), 30 deletions(-) diff --git a/internal/dataexchange/ffdx/dxevent.go b/internal/dataexchange/ffdx/dxevent.go index cf91e3e08d..b125fe7b26 100644 --- a/internal/dataexchange/ffdx/dxevent.go +++ b/internal/dataexchange/ffdx/dxevent.go @@ -17,6 +17,8 @@ package ffdx import ( + "strings" + "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly-common/pkg/i18n" "github.com/hyperledger/firefly-common/pkg/log" @@ -154,8 +156,10 @@ func (h *FFDX) dispatchEvent(msg *wsEvent) { var hash *fftypes.Bytes32 hash, err = fftypes.ParseBytes32(h.ctx, msg.Hash) if err == nil { + pathParts := strings.Split(msg.Path, "/") e.dxType = dataexchange.DXEventTypePrivateBlobReceived e.privateBlobReceived = &dataexchange.PrivateBlobReceived{ + Namespace: pathParts[0], PeerID: msg.Sender, Hash: *hash, Size: msg.Size, diff --git a/internal/dataexchange/ffdx/ffdx.go b/internal/dataexchange/ffdx/ffdx.go index 1447a27933..eed9b14b79 100644 --- a/internal/dataexchange/ffdx/ffdx.go +++ b/internal/dataexchange/ffdx/ffdx.go @@ -39,7 +39,7 @@ import ( type FFDX struct { ctx context.Context capabilities *dataexchange.Capabilities - callbacks dataexchange.Callbacks + callbacks callbacks client *resty.Client wsconn wsclient.WSClient needsInit bool @@ -49,6 +49,16 @@ type FFDX struct { ackChannel chan *ack } +type callbacks struct { + listeners []dataexchange.Callbacks +} + +func (cb *callbacks) DXEvent(event dataexchange.DXEvent) { + for _, cb := range cb.listeners { + cb.DXEvent(event) + } +} + const ( dxHTTPHeaderHash = "dx-hash" dxHTTPHeaderSize = "dx-size" @@ -138,8 +148,8 @@ func (h *FFDX) SetNodes(nodes []fftypes.JSONObject) { h.nodes = nodes } -func (h *FFDX) RegisterListener(callbacks dataexchange.Callbacks) { - h.callbacks = callbacks +func (h *FFDX) RegisterListener(listener dataexchange.Callbacks) { + h.callbacks.listeners = append(h.callbacks.listeners, listener) } func (h *FFDX) Start() error { diff --git a/internal/dataexchange/ffdx/ffdx_test.go b/internal/dataexchange/ffdx/ffdx_test.go index 04281bdbfc..25a37476dd 100644 --- a/internal/dataexchange/ffdx/ffdx_test.go +++ b/internal/dataexchange/ffdx/ffdx_test.go @@ -443,7 +443,7 @@ func TestEvents(t *testing.T) { assert.Equal(t, `{"action":"ack","id":"0"}`, string(msg)) mcb := &dataexchangemocks.Callbacks{} - h.callbacks = mcb + h.RegisterListener(mcb) mcb.On("DXEvent", mock.MatchedBy(func(ev dataexchange.DXEvent) bool { return ev.NamespacedID() == "1" && @@ -557,7 +557,7 @@ func TestEventsWithManifest(t *testing.T) { assert.Equal(t, `{"action":"ack","id":"0"}`, string(msg)) mcb := &dataexchangemocks.Callbacks{} - h.callbacks = mcb + h.RegisterListener(mcb) mcb.On("DXEvent", mock.MatchedBy(func(ev dataexchange.DXEvent) bool { return ev.NamespacedID() == "1" && @@ -585,7 +585,7 @@ func TestEventLoopReceiveClosed(t *testing.T) { wsm := &wsmocks.WSClient{} h := &FFDX{ ctx: context.Background(), - callbacks: dxc, + callbacks: callbacks{listeners: []dataexchange.Callbacks{dxc}}, wsconn: wsm, } r := make(chan []byte) @@ -601,7 +601,7 @@ func TestEventLoopSendClosed(t *testing.T) { ctx, cancelCtx := context.WithCancel(context.Background()) h := &FFDX{ ctx: ctx, - callbacks: dxc, + callbacks: callbacks{listeners: []dataexchange.Callbacks{dxc}}, wsconn: wsm, ackChannel: make(chan *ack, 1), } @@ -622,7 +622,7 @@ func TestEventLoopClosedContext(t *testing.T) { cancel() h := &FFDX{ ctx: ctx, - callbacks: dxc, + callbacks: callbacks{listeners: []dataexchange.Callbacks{dxc}}, wsconn: wsm, } r := make(chan []byte, 1) diff --git a/internal/events/dx_callbacks.go b/internal/events/dx_callbacks.go index 1b91174bcd..a873fa9472 100644 --- a/internal/events/dx_callbacks.go +++ b/internal/events/dx_callbacks.go @@ -185,7 +185,7 @@ func (em *eventManager) messageReceived(dx dataexchange.Plugin, event dataexchan mr := event.MessageReceived() - // De-serializae the transport wrapper + // De-serialize the transport wrapper var wrapper *core.TransportWrapper err := json.Unmarshal(mr.Data, &wrapper) if err != nil { @@ -198,6 +198,10 @@ func (em *eventManager) messageReceived(dx dataexchange.Plugin, event dataexchan event.AckWithManifest("") return } + if wrapper.Batch.Namespace != em.namespace { + log.L(em.ctx).Debugf("Ignoring batch from wrong namespace '%s'", wrapper.Batch.Namespace) + return + } l.Infof("Private batch received from %s peer '%s' (len=%d)", dx.Name(), mr.PeerID, len(mr.Data)) manifestString, err := em.privateBatchReceived(mr.PeerID, wrapper.Batch, wrapper.Group) @@ -218,6 +222,10 @@ func (em *eventManager) privateBlobReceived(dx dataexchange.Plugin, event dataex event.Ack() // Still confirm the event return } + if br.Namespace != em.namespace { + log.L(em.ctx).Debugf("Ignoring blob from wrong namespace '%s'", br.Namespace) + return + } // Dispatch to the blob receiver for efficient batch DB operations em.blobReceiver.blobReceived(em.ctx, &blobNotification{ diff --git a/internal/events/dx_callbacks_test.go b/internal/events/dx_callbacks_test.go index d64c323467..a24840d86a 100644 --- a/internal/events/dx_callbacks_test.go +++ b/internal/events/dx_callbacks_test.go @@ -20,6 +20,7 @@ import ( "context" "encoding/json" "fmt" + "strings" "testing" "github.com/hyperledger/firefly-common/pkg/fftypes" @@ -99,7 +100,9 @@ func newMessageReceived(peerID string, data []byte, expectedManifest string) *da func newPrivateBlobReceivedNoAck(peerID string, hash *fftypes.Bytes32, size int64, payloadRef string) *dataexchangemocks.DXEvent { mde := &dataexchangemocks.DXEvent{} + pathParts := strings.Split(payloadRef, "/") mde.On("PrivateBlobReceived").Return(&dataexchange.PrivateBlobReceived{ + Namespace: pathParts[0], PeerID: peerID, Hash: *hash, Size: size, diff --git a/internal/identity/tbd/tbd.go b/internal/identity/tbd/tbd.go index 507d8aedf0..197d9269c6 100644 --- a/internal/identity/tbd/tbd.go +++ b/internal/identity/tbd/tbd.go @@ -26,7 +26,6 @@ import ( // TBD is a null implementation of the Identity Interface to avoid breaking configuration created with the previous "onchain" plugin type TBD struct { capabilities *identity.Capabilities - callbacks identity.Callbacks } func (tbd *TBD) Name() string { @@ -38,8 +37,7 @@ func (tbd *TBD) Init(ctx context.Context, config config.Section) (err error) { return nil } -func (tbd *TBD) RegisterListener(callbacks identity.Callbacks) { - tbd.callbacks = callbacks +func (tbd *TBD) RegisterListener(listener identity.Callbacks) { } func (tbd *TBD) Start() error { diff --git a/internal/sharedstorage/ipfs/ipfs.go b/internal/sharedstorage/ipfs/ipfs.go index e9d4d12020..a7d878ca48 100644 --- a/internal/sharedstorage/ipfs/ipfs.go +++ b/internal/sharedstorage/ipfs/ipfs.go @@ -35,7 +35,6 @@ import ( type IPFS struct { ctx context.Context capabilities *sharedstorage.Capabilities - callbacks sharedstorage.Callbacks apiClient *resty.Client gwClient *resty.Client } @@ -68,8 +67,7 @@ func (i *IPFS) Init(ctx context.Context, config config.Section) error { return nil } -func (i *IPFS) RegisterListener(callbacks sharedstorage.Callbacks) { - i.callbacks = callbacks +func (i *IPFS) RegisterListener(listener sharedstorage.Callbacks) { } func (i *IPFS) Capabilities() *sharedstorage.Capabilities { diff --git a/mocks/blockchainmocks/plugin.go b/mocks/blockchainmocks/plugin.go index 890424ea26..11eeebac0f 100644 --- a/mocks/blockchainmocks/plugin.go +++ b/mocks/blockchainmocks/plugin.go @@ -268,9 +268,9 @@ func (_m *Plugin) QueryContract(ctx context.Context, location *fftypes.JSONAny, return r0, r1 } -// RegisterListener provides a mock function with given fields: callbacks -func (_m *Plugin) RegisterListener(callbacks blockchain.Callbacks) { - _m.Called(callbacks) +// RegisterListener provides a mock function with given fields: listener +func (_m *Plugin) RegisterListener(listener blockchain.Callbacks) { + _m.Called(listener) } // Start provides a mock function with given fields: diff --git a/mocks/dataexchangemocks/plugin.go b/mocks/dataexchangemocks/plugin.go index 0bae603467..7f8268aa01 100644 --- a/mocks/dataexchangemocks/plugin.go +++ b/mocks/dataexchangemocks/plugin.go @@ -160,9 +160,9 @@ func (_m *Plugin) Name() string { return r0 } -// RegisterListener provides a mock function with given fields: callbacks -func (_m *Plugin) RegisterListener(callbacks dataexchange.Callbacks) { - _m.Called(callbacks) +// RegisterListener provides a mock function with given fields: listener +func (_m *Plugin) RegisterListener(listener dataexchange.Callbacks) { + _m.Called(listener) } // SendMessage provides a mock function with given fields: ctx, nsOpID, peerID, data diff --git a/mocks/identitymocks/plugin.go b/mocks/identitymocks/plugin.go index d739d8d0d3..8cb0c62fe5 100644 --- a/mocks/identitymocks/plugin.go +++ b/mocks/identitymocks/plugin.go @@ -66,9 +66,9 @@ func (_m *Plugin) Name() string { return r0 } -// RegisterListener provides a mock function with given fields: callbacks -func (_m *Plugin) RegisterListener(callbacks identity.Callbacks) { - _m.Called(callbacks) +// RegisterListener provides a mock function with given fields: listener +func (_m *Plugin) RegisterListener(listener identity.Callbacks) { + _m.Called(listener) } // Start provides a mock function with given fields: diff --git a/mocks/sharedstoragemocks/plugin.go b/mocks/sharedstoragemocks/plugin.go index c6fc4c85fa..2e1f13529e 100644 --- a/mocks/sharedstoragemocks/plugin.go +++ b/mocks/sharedstoragemocks/plugin.go @@ -91,9 +91,9 @@ func (_m *Plugin) Name() string { return r0 } -// RegisterListener provides a mock function with given fields: callbacks -func (_m *Plugin) RegisterListener(callbacks sharedstorage.Callbacks) { - _m.Called(callbacks) +// RegisterListener provides a mock function with given fields: listener +func (_m *Plugin) RegisterListener(listener sharedstorage.Callbacks) { + _m.Called(listener) } // UploadData provides a mock function with given fields: ctx, data diff --git a/pkg/dataexchange/plugin.go b/pkg/dataexchange/plugin.go index bdb6e7ff38..3a6db6e4ff 100644 --- a/pkg/dataexchange/plugin.go +++ b/pkg/dataexchange/plugin.go @@ -67,7 +67,7 @@ type Plugin interface { SetNodes(nodes []fftypes.JSONObject) // RegisterListener registers a listener to receive callbacks - RegisterListener(callbacks Callbacks) + RegisterListener(listener Callbacks) // Data exchange interface must not deliver any events until start is called Start() error @@ -129,6 +129,7 @@ type MessageReceived struct { } type PrivateBlobReceived struct { + Namespace string PeerID string Hash fftypes.Bytes32 Size int64 diff --git a/pkg/identity/plugin.go b/pkg/identity/plugin.go index 6f250e6002..59c9f5248d 100644 --- a/pkg/identity/plugin.go +++ b/pkg/identity/plugin.go @@ -34,7 +34,7 @@ type Plugin interface { Init(ctx context.Context, config config.Section) error // RegisterListener registers a listener to receive callbacks - RegisterListener(callbacks Callbacks) + RegisterListener(listener Callbacks) // Blockchain interface must not deliver any events until start is called Start() error diff --git a/pkg/sharedstorage/plugin.go b/pkg/sharedstorage/plugin.go index 1045353ea5..4c65855125 100644 --- a/pkg/sharedstorage/plugin.go +++ b/pkg/sharedstorage/plugin.go @@ -35,7 +35,7 @@ type Plugin interface { Init(ctx context.Context, config config.Section) error // RegisterListener registers a listener to receive callbacks - RegisterListener(callbacks Callbacks) + RegisterListener(listener Callbacks) // Capabilities returns capabilities - not called until after Init Capabilities() *Capabilities From 588c8f8ae02e07171a26b730df3fc6a2b8d2531a Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Thu, 9 Jun 2022 12:56:34 -0400 Subject: [PATCH 24/33] Database plugin can track multiple listeners Each listener will ignore events outside its namespace. Signed-off-by: Andrew Richardson --- internal/database/postgres/postgres.go | 4 +- .../sqlcommon/contractapis_sql_test.go | 2 +- internal/database/sqlcommon/sqlcommon.go | 40 ++++++- .../database/sqlcommon/tokenpool_sql_test.go | 2 +- internal/database/sqlite3/sqlite3.go | 4 +- internal/namespace/manager.go | 3 +- internal/namespace/manager_test.go | 3 + internal/namespace/persistence_events.go | 73 ++++++++++++ internal/namespace/persistence_events_test.go | 107 ++++++++++++++++++ internal/orchestrator/orchestrator.go | 13 +-- internal/orchestrator/orchestrator_test.go | 2 - internal/orchestrator/persistence_events.go | 51 +++------ .../orchestrator/persistence_events_test.go | 64 ++--------- mocks/databasemocks/plugin.go | 6 +- pkg/database/plugin.go | 2 +- 15 files changed, 264 insertions(+), 112 deletions(-) create mode 100644 internal/namespace/persistence_events.go create mode 100644 internal/namespace/persistence_events_test.go diff --git a/internal/database/postgres/postgres.go b/internal/database/postgres/postgres.go index 90d5b067e1..a047ccd859 100644 --- a/internal/database/postgres/postgres.go +++ b/internal/database/postgres/postgres.go @@ -42,8 +42,8 @@ func (psql *Postgres) Init(ctx context.Context, config config.Section) error { return psql.SQLCommon.Init(ctx, psql, config, capabilities) } -func (psql *Postgres) RegisterListener(callbacks database.Callbacks) { - psql.SQLCommon.RegisterListener(callbacks) +func (psql *Postgres) RegisterListener(listener database.Callbacks) { + psql.SQLCommon.RegisterListener(listener) } func (psql *Postgres) Name() string { diff --git a/internal/database/sqlcommon/contractapis_sql_test.go b/internal/database/sqlcommon/contractapis_sql_test.go index fc601531fe..9a8868697f 100644 --- a/internal/database/sqlcommon/contractapis_sql_test.go +++ b/internal/database/sqlcommon/contractapis_sql_test.go @@ -126,7 +126,7 @@ func TestContractAPIDBFailUpdate(t *testing.T) { func TestUpsertContractAPIIDMismatch(t *testing.T) { s, db := newMockProvider().init() callbacks := &databasemocks.Callbacks{} - s.SQLCommon.callbacks = callbacks + s.RegisterListener(callbacks) apiID := fftypes.NewUUID() api := &core.ContractAPI{ ID: apiID, diff --git a/internal/database/sqlcommon/sqlcommon.go b/internal/database/sqlcommon/sqlcommon.go index fc5d45b0ee..770be69730 100644 --- a/internal/database/sqlcommon/sqlcommon.go +++ b/internal/database/sqlcommon/sqlcommon.go @@ -39,11 +39,45 @@ import ( type SQLCommon struct { db *sql.DB capabilities *database.Capabilities - callbacks database.Callbacks + callbacks callbacks provider Provider features SQLFeatures } +type callbacks struct { + listeners []database.Callbacks +} + +func (cb *callbacks) OrderedUUIDCollectionNSEvent(resType database.OrderedUUIDCollectionNS, eventType core.ChangeEventType, ns string, id *fftypes.UUID, sequence int64) { + for _, cb := range cb.listeners { + cb.OrderedUUIDCollectionNSEvent(resType, eventType, ns, id, sequence) + } +} + +func (cb *callbacks) OrderedCollectionNSEvent(resType database.OrderedCollectionNS, eventType core.ChangeEventType, ns string, sequence int64) { + for _, cb := range cb.listeners { + cb.OrderedCollectionNSEvent(resType, eventType, ns, sequence) + } +} + +func (cb *callbacks) UUIDCollectionNSEvent(resType database.UUIDCollectionNS, eventType core.ChangeEventType, ns string, id *fftypes.UUID) { + for _, cb := range cb.listeners { + cb.UUIDCollectionNSEvent(resType, eventType, ns, id) + } +} + +func (cb *callbacks) UUIDCollectionEvent(resType database.UUIDCollection, eventType core.ChangeEventType, id *fftypes.UUID) { + for _, cb := range cb.listeners { + cb.UUIDCollectionEvent(resType, eventType, id) + } +} + +func (cb *callbacks) HashCollectionNSEvent(resType database.HashCollectionNS, eventType core.ChangeEventType, ns string, hash *fftypes.Bytes32) { + for _, cb := range cb.listeners { + cb.HashCollectionNSEvent(resType, eventType, ns, hash) + } +} + type txContextKey struct{} type txWrapper struct { @@ -96,8 +130,8 @@ func (s *SQLCommon) Init(ctx context.Context, provider Provider, config config.S return nil } -func (s *SQLCommon) RegisterListener(callbacks database.Callbacks) { - s.callbacks = callbacks +func (s *SQLCommon) RegisterListener(listener database.Callbacks) { + s.callbacks.listeners = append(s.callbacks.listeners, listener) } func (s *SQLCommon) Capabilities() *database.Capabilities { return s.capabilities } diff --git a/internal/database/sqlcommon/tokenpool_sql_test.go b/internal/database/sqlcommon/tokenpool_sql_test.go index 8e8e60439b..db12d4bdf1 100644 --- a/internal/database/sqlcommon/tokenpool_sql_test.go +++ b/internal/database/sqlcommon/tokenpool_sql_test.go @@ -176,7 +176,7 @@ func TestUpsertTokenPoolFailCommit(t *testing.T) { func TestUpsertTokenPoolUpdateIDMismatch(t *testing.T) { s, db := newMockProvider().init() callbacks := &databasemocks.Callbacks{} - s.SQLCommon.callbacks = callbacks + s.RegisterListener(callbacks) poolID := fftypes.NewUUID() pool := &core.TokenPool{ ID: poolID, diff --git a/internal/database/sqlite3/sqlite3.go b/internal/database/sqlite3/sqlite3.go index 73879dd755..d0eafb3d42 100644 --- a/internal/database/sqlite3/sqlite3.go +++ b/internal/database/sqlite3/sqlite3.go @@ -58,8 +58,8 @@ func (sqlite *SQLite3) Init(ctx context.Context, config config.Section) error { return sqlite.SQLCommon.Init(ctx, sqlite, config, capabilities) } -func (sqlite *SQLite3) RegisterListener(callbacks database.Callbacks) { - sqlite.SQLCommon.RegisterListener(callbacks) +func (sqlite *SQLite3) RegisterListener(listener database.Callbacks) { + sqlite.SQLCommon.RegisterListener(listener) } func (sqlite *SQLite3) Name() string { diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index 3214fd7f6d..2248150590 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -199,7 +199,7 @@ func (nm *namespaceManager) Init(ctx context.Context, cancelCtx context.CancelFu func (nm *namespaceManager) initNamespace(name string, ns *namespace) error { or := nm.utOrchestrator if or == nil { - or = orchestrator.NewOrchestrator(name, ns.config, ns.plugins, nm.metrics, nm.adminEvents) + or = orchestrator.NewOrchestrator(name, ns.config, ns.plugins, nm.metrics) } if err := or.Init(nm.ctx, nm.cancelCtx); err != nil { return err @@ -553,6 +553,7 @@ func (nm *namespaceManager) initPlugins(ctx context.Context) (err error) { if err = entry.plugin.Init(ctx, entry.config); err != nil { return err } + entry.plugin.RegisterListener(nm) } for _, entry := range nm.plugins.blockchain { if err = entry.plugin.Init(ctx, entry.config, nm.metrics); err != nil { diff --git a/internal/namespace/manager_test.go b/internal/namespace/manager_test.go index 1226a6697d..2b3391c800 100644 --- a/internal/namespace/manager_test.go +++ b/internal/namespace/manager_test.go @@ -125,6 +125,7 @@ func TestInit(t *testing.T) { nm.utOrchestrator = mo nm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mdi.On("RegisterListener", mock.Anything).Return() nm.mbi.On("Init", mock.Anything, mock.Anything, nm.mmi).Return(nil) nm.mdx.On("Init", mock.Anything, mock.Anything).Return(nil) nm.mps.On("Init", mock.Anything, mock.Anything).Return(nil) @@ -149,6 +150,7 @@ func TestInitVersion1(t *testing.T) { nm.utOrchestrator = mo nm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mdi.On("RegisterListener", mock.Anything).Return() nm.mbi.On("Init", mock.Anything, mock.Anything, nm.mmi).Return(nil) nm.mdx.On("Init", mock.Anything, mock.Anything).Return(nil) nm.mps.On("Init", mock.Anything, mock.Anything).Return(nil) @@ -174,6 +176,7 @@ func TestInitVersion1Fail(t *testing.T) { nm.utOrchestrator = mo nm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mdi.On("RegisterListener", mock.Anything).Return() nm.mbi.On("Init", mock.Anything, mock.Anything, nm.mmi).Return(nil) nm.mdx.On("Init", mock.Anything, mock.Anything).Return(nil) nm.mps.On("Init", mock.Anything, mock.Anything).Return(nil) diff --git a/internal/namespace/persistence_events.go b/internal/namespace/persistence_events.go new file mode 100644 index 0000000000..38772529c5 --- /dev/null +++ b/internal/namespace/persistence_events.go @@ -0,0 +1,73 @@ +// Copyright © 2022 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 namespace + +import ( + "github.com/hyperledger/firefly-common/pkg/fftypes" + "github.com/hyperledger/firefly/pkg/core" + "github.com/hyperledger/firefly/pkg/database" +) + +func (nm *namespaceManager) OrderedUUIDCollectionNSEvent(resType database.OrderedUUIDCollectionNS, eventType core.ChangeEventType, ns string, id *fftypes.UUID, sequence int64) { + var ces *int64 + if eventType == core.ChangeEventTypeCreated { + // Sequence is only provided on create events + ces = &sequence + } + nm.adminEvents.Dispatch(&core.ChangeEvent{ + Collection: string(resType), + Type: eventType, + Namespace: ns, + ID: id, + Sequence: ces, + }) +} + +func (nm *namespaceManager) OrderedCollectionNSEvent(resType database.OrderedCollectionNS, eventType core.ChangeEventType, ns string, sequence int64) { + nm.adminEvents.Dispatch(&core.ChangeEvent{ + Collection: string(resType), + Type: eventType, + Namespace: ns, + Sequence: &sequence, + }) +} + +func (nm *namespaceManager) UUIDCollectionNSEvent(resType database.UUIDCollectionNS, eventType core.ChangeEventType, ns string, id *fftypes.UUID) { + nm.adminEvents.Dispatch(&core.ChangeEvent{ + Collection: string(resType), + Type: eventType, + Namespace: ns, + ID: id, + }) +} + +func (nm *namespaceManager) UUIDCollectionEvent(resType database.UUIDCollection, eventType core.ChangeEventType, id *fftypes.UUID) { + nm.adminEvents.Dispatch(&core.ChangeEvent{ + Collection: string(resType), + Type: eventType, + ID: id, + }) +} + +func (nm *namespaceManager) HashCollectionNSEvent(resType database.HashCollectionNS, eventType core.ChangeEventType, ns string, hash *fftypes.Bytes32) { + nm.adminEvents.Dispatch(&core.ChangeEvent{ + Collection: string(resType), + Type: eventType, + Namespace: ns, + Hash: hash, + }) +} diff --git a/internal/namespace/persistence_events_test.go b/internal/namespace/persistence_events_test.go new file mode 100644 index 0000000000..4746b38a14 --- /dev/null +++ b/internal/namespace/persistence_events_test.go @@ -0,0 +1,107 @@ +// 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 namespace + +import ( + "testing" + + "github.com/hyperledger/firefly-common/pkg/fftypes" + "github.com/hyperledger/firefly/mocks/spieventsmocks" + "github.com/hyperledger/firefly/pkg/core" + "github.com/hyperledger/firefly/pkg/database" + "github.com/stretchr/testify/mock" +) + +func TestMessageCreated(t *testing.T) { + mae := &spieventsmocks.Manager{} + nm := &namespaceManager{ + adminEvents: mae, + } + mae.On("Dispatch", mock.Anything).Return() + nm.OrderedUUIDCollectionNSEvent(database.CollectionMessages, core.ChangeEventTypeCreated, "ns1", fftypes.NewUUID(), 12345) + mae.AssertExpectations(t) +} + +func TestPinCreated(t *testing.T) { + mae := &spieventsmocks.Manager{} + nm := &namespaceManager{ + adminEvents: mae, + } + mae.On("Dispatch", mock.Anything).Return() + nm.OrderedCollectionNSEvent(database.CollectionPins, core.ChangeEventTypeCreated, "ns1", 12345) + mae.AssertExpectations(t) +} + +func TestEventCreated(t *testing.T) { + mae := &spieventsmocks.Manager{} + nm := &namespaceManager{ + adminEvents: mae, + } + mae.On("Dispatch", mock.Anything).Return() + nm.OrderedUUIDCollectionNSEvent(database.CollectionEvents, core.ChangeEventTypeCreated, "ns1", fftypes.NewUUID(), 12345) + mae.AssertExpectations(t) +} + +func TestSubscriptionCreated(t *testing.T) { + mae := &spieventsmocks.Manager{} + nm := &namespaceManager{ + adminEvents: mae, + } + mae.On("Dispatch", mock.Anything).Return() + nm.UUIDCollectionNSEvent(database.CollectionSubscriptions, core.ChangeEventTypeCreated, "ns1", fftypes.NewUUID()) + mae.AssertExpectations(t) +} + +func TestSubscriptionUpdated(t *testing.T) { + mae := &spieventsmocks.Manager{} + nm := &namespaceManager{ + adminEvents: mae, + } + mae.On("Dispatch", mock.Anything).Return() + nm.UUIDCollectionNSEvent(database.CollectionSubscriptions, core.ChangeEventTypeUpdated, "ns1", fftypes.NewUUID()) + mae.AssertExpectations(t) +} + +func TestSubscriptionDeleted(t *testing.T) { + mae := &spieventsmocks.Manager{} + nm := &namespaceManager{ + adminEvents: mae, + } + mae.On("Dispatch", mock.Anything).Return() + nm.UUIDCollectionNSEvent(database.CollectionSubscriptions, core.ChangeEventTypeDeleted, "ns1", fftypes.NewUUID()) + mae.AssertExpectations(t) +} + +func TestUUIDCollectionEventFull(t *testing.T) { + mae := &spieventsmocks.Manager{} + nm := &namespaceManager{ + adminEvents: mae, + } + mae.On("Dispatch", mock.Anything).Return() + nm.UUIDCollectionEvent(database.CollectionNamespaces, core.ChangeEventTypeDeleted, fftypes.NewUUID()) + mae.AssertExpectations(t) +} + +func TestHashCollectionNSEventOk(t *testing.T) { + mae := &spieventsmocks.Manager{} + nm := &namespaceManager{ + adminEvents: mae, + } + mae.On("Dispatch", mock.Anything).Return() + nm.HashCollectionNSEvent(database.CollectionGroups, core.ChangeEventTypeDeleted, "ns1", fftypes.NewRandB32()) + mae.AssertExpectations(t) +} diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 111facbbde..aed19cefcd 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -37,7 +37,6 @@ import ( "github.com/hyperledger/firefly/internal/operations" "github.com/hyperledger/firefly/internal/privatemessaging" "github.com/hyperledger/firefly/internal/shareddownload" - "github.com/hyperledger/firefly/internal/spievents" "github.com/hyperledger/firefly/internal/syncasync" "github.com/hyperledger/firefly/internal/txcommon" "github.com/hyperledger/firefly/pkg/blockchain" @@ -193,16 +192,14 @@ type orchestrator struct { operations operations.Manager sharedDownload shareddownload.Manager txHelper txcommon.Helper - adminEvents spievents.Manager } -func NewOrchestrator(ns string, config Config, plugins Plugins, metrics metrics.Manager, adminEvents spievents.Manager) Orchestrator { +func NewOrchestrator(ns string, config Config, plugins Plugins, metrics metrics.Manager) Orchestrator { or := &orchestrator{ - namespace: ns, - config: config, - plugins: plugins, - metrics: metrics, - adminEvents: adminEvents, + namespace: ns, + config: config, + plugins: plugins, + metrics: metrics, } return or } diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index 7fa087eb46..d85541e45c 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -149,7 +149,6 @@ func newTestOrchestrator() *testOrchestrator { tor.orchestrator.operations = tor.mom tor.orchestrator.batchpin = tor.mbp tor.orchestrator.sharedDownload = tor.msd - tor.orchestrator.adminEvents = tor.mae tor.orchestrator.txHelper = tor.mth tor.orchestrator.definitions = tor.mdh tor.orchestrator.plugins.Blockchain.Plugin = tor.mbi @@ -179,7 +178,6 @@ func TestNewOrchestrator(t *testing.T) { Config{}, Plugins{}, &metricsmocks.Manager{}, - &spieventsmocks.Manager{}, ) assert.NotNil(t, or) } diff --git a/internal/orchestrator/persistence_events.go b/internal/orchestrator/persistence_events.go index ab084913eb..1374682921 100644 --- a/internal/orchestrator/persistence_events.go +++ b/internal/orchestrator/persistence_events.go @@ -18,44 +18,39 @@ package orchestrator import ( "github.com/hyperledger/firefly-common/pkg/fftypes" + "github.com/hyperledger/firefly-common/pkg/log" "github.com/hyperledger/firefly/pkg/core" "github.com/hyperledger/firefly/pkg/database" ) func (or *orchestrator) OrderedUUIDCollectionNSEvent(resType database.OrderedUUIDCollectionNS, eventType core.ChangeEventType, ns string, id *fftypes.UUID, sequence int64) { + if ns != or.namespace { + log.L(or.ctx).Debugf("Ignoring database event from wrong namespace '%s'", ns) + return + } switch { case eventType == core.ChangeEventTypeCreated && resType == database.CollectionMessages: or.batch.NewMessages() <- sequence case eventType == core.ChangeEventTypeCreated && resType == database.CollectionEvents: or.events.NewEvents() <- sequence } - var ces *int64 - if eventType == core.ChangeEventTypeCreated { - // Sequence is only provided on create events - ces = &sequence - } - or.adminEvents.Dispatch(&core.ChangeEvent{ - Collection: string(resType), - Type: eventType, - Namespace: ns, - ID: id, - Sequence: ces, - }) } func (or *orchestrator) OrderedCollectionNSEvent(resType database.OrderedCollectionNS, eventType core.ChangeEventType, ns string, sequence int64) { + if ns != or.namespace { + log.L(or.ctx).Debugf("Ignoring database event from wrong namespace '%s'", ns) + return + } if eventType == core.ChangeEventTypeCreated && resType == database.CollectionPins { or.events.NewPins() <- sequence } - or.adminEvents.Dispatch(&core.ChangeEvent{ - Collection: string(resType), - Type: eventType, - Namespace: ns, - Sequence: &sequence, - }) } func (or *orchestrator) UUIDCollectionNSEvent(resType database.UUIDCollectionNS, eventType core.ChangeEventType, ns string, id *fftypes.UUID) { + if ns != or.namespace { + log.L(or.ctx).Debugf("Ignoring database event from wrong namespace '%s'", ns) + return + } switch { case eventType == core.ChangeEventTypeCreated && resType == database.CollectionSubscriptions: or.events.NewSubscriptions() <- id @@ -64,28 +59,12 @@ func (or *orchestrator) UUIDCollectionNSEvent(resType database.UUIDCollectionNS, case eventType == core.ChangeEventTypeUpdated && resType == database.CollectionSubscriptions: or.events.SubscriptionUpdates() <- id } - or.adminEvents.Dispatch(&core.ChangeEvent{ - Collection: string(resType), - Type: eventType, - Namespace: ns, - ID: id, - }) } func (or *orchestrator) UUIDCollectionEvent(resType database.UUIDCollection, eventType core.ChangeEventType, id *fftypes.UUID) { - or.adminEvents.Dispatch(&core.ChangeEvent{ - Collection: string(resType), - Type: eventType, - ID: id, - }) + // do nothing } func (or *orchestrator) HashCollectionNSEvent(resType database.HashCollectionNS, eventType core.ChangeEventType, ns string, hash *fftypes.Bytes32) { - or.adminEvents.Dispatch(&core.ChangeEvent{ - Collection: string(resType), - Type: eventType, - Namespace: ns, - Hash: hash, - }) - + // do nothing } diff --git a/internal/orchestrator/persistence_events_test.go b/internal/orchestrator/persistence_events_test.go index dd161f8606..e78d7e6e1f 100644 --- a/internal/orchestrator/persistence_events_test.go +++ b/internal/orchestrator/persistence_events_test.go @@ -22,112 +22,72 @@ import ( "github.com/hyperledger/firefly-common/pkg/fftypes" "github.com/hyperledger/firefly/mocks/batchmocks" "github.com/hyperledger/firefly/mocks/eventmocks" - "github.com/hyperledger/firefly/mocks/spieventsmocks" "github.com/hyperledger/firefly/pkg/core" "github.com/hyperledger/firefly/pkg/database" - "github.com/stretchr/testify/mock" ) func TestMessageCreated(t *testing.T) { mb := &batchmocks.Manager{} - mae := &spieventsmocks.Manager{} o := &orchestrator{ - batch: mb, - adminEvents: mae, + namespace: "ns1", + batch: mb, } mb.On("NewMessages").Return((chan<- int64)(make(chan int64, 1))) - mae.On("Dispatch", mock.Anything).Return() o.OrderedUUIDCollectionNSEvent(database.CollectionMessages, core.ChangeEventTypeCreated, "ns1", fftypes.NewUUID(), 12345) mb.AssertExpectations(t) - mae.AssertExpectations(t) } func TestPinCreated(t *testing.T) { mem := &eventmocks.EventManager{} - mae := &spieventsmocks.Manager{} o := &orchestrator{ - adminEvents: mae, - events: mem, + namespace: "ns1", + events: mem, } - mae.On("Dispatch", mock.Anything).Return() mem.On("NewPins").Return((chan<- int64)(make(chan int64, 1))) o.OrderedCollectionNSEvent(database.CollectionPins, core.ChangeEventTypeCreated, "ns1", 12345) mem.AssertExpectations(t) - mae.AssertExpectations(t) } func TestEventCreated(t *testing.T) { mem := &eventmocks.EventManager{} - mae := &spieventsmocks.Manager{} o := &orchestrator{ - adminEvents: mae, - events: mem, + namespace: "ns1", + events: mem, } - mae.On("Dispatch", mock.Anything).Return() mem.On("NewEvents").Return((chan<- int64)(make(chan int64, 1))) o.OrderedUUIDCollectionNSEvent(database.CollectionEvents, core.ChangeEventTypeCreated, "ns1", fftypes.NewUUID(), 12345) mem.AssertExpectations(t) - mae.AssertExpectations(t) } func TestSubscriptionCreated(t *testing.T) { mem := &eventmocks.EventManager{} - mae := &spieventsmocks.Manager{} o := &orchestrator{ - adminEvents: mae, - events: mem, + namespace: "ns1", + events: mem, } - mae.On("Dispatch", mock.Anything).Return() mem.On("NewSubscriptions").Return((chan<- *fftypes.UUID)(make(chan *fftypes.UUID, 1))) o.UUIDCollectionNSEvent(database.CollectionSubscriptions, core.ChangeEventTypeCreated, "ns1", fftypes.NewUUID()) mem.AssertExpectations(t) - mae.AssertExpectations(t) } func TestSubscriptionUpdated(t *testing.T) { mem := &eventmocks.EventManager{} - mae := &spieventsmocks.Manager{} o := &orchestrator{ - adminEvents: mae, - events: mem, + namespace: "ns1", + events: mem, } - mae.On("Dispatch", mock.Anything).Return() mem.On("SubscriptionUpdates").Return((chan<- *fftypes.UUID)(make(chan *fftypes.UUID, 1))) o.UUIDCollectionNSEvent(database.CollectionSubscriptions, core.ChangeEventTypeUpdated, "ns1", fftypes.NewUUID()) mem.AssertExpectations(t) - mae.AssertExpectations(t) } func TestSubscriptionDeleted(t *testing.T) { mem := &eventmocks.EventManager{} - mae := &spieventsmocks.Manager{} o := &orchestrator{ - adminEvents: mae, - events: mem, + namespace: "ns1", + events: mem, } - mae.On("Dispatch", mock.Anything).Return() mem.On("DeletedSubscriptions").Return((chan<- *fftypes.UUID)(make(chan *fftypes.UUID, 1))) o.UUIDCollectionNSEvent(database.CollectionSubscriptions, core.ChangeEventTypeDeleted, "ns1", fftypes.NewUUID()) mem.AssertExpectations(t) - mae.AssertExpectations(t) -} - -func TestUUIDCollectionEventFull(t *testing.T) { - mae := &spieventsmocks.Manager{} - o := &orchestrator{ - adminEvents: mae, - } - mae.On("Dispatch", mock.Anything).Return() - o.UUIDCollectionEvent(database.CollectionNamespaces, core.ChangeEventTypeDeleted, fftypes.NewUUID()) - mae.AssertExpectations(t) -} - -func TestHashCollectionNSEventOk(t *testing.T) { - mae := &spieventsmocks.Manager{} - o := &orchestrator{ - adminEvents: mae, - } - mae.On("Dispatch", mock.Anything).Return() - o.HashCollectionNSEvent(database.CollectionGroups, core.ChangeEventTypeDeleted, "ns1", fftypes.NewRandB32()) - mae.AssertExpectations(t) } diff --git a/mocks/databasemocks/plugin.go b/mocks/databasemocks/plugin.go index 93c7c0afbc..37e33d2399 100644 --- a/mocks/databasemocks/plugin.go +++ b/mocks/databasemocks/plugin.go @@ -2460,9 +2460,9 @@ func (_m *Plugin) Name() string { return r0 } -// RegisterListener provides a mock function with given fields: callbacks -func (_m *Plugin) RegisterListener(callbacks database.Callbacks) { - _m.Called(callbacks) +// RegisterListener provides a mock function with given fields: listener +func (_m *Plugin) RegisterListener(listener database.Callbacks) { + _m.Called(listener) } // ReplaceMessage provides a mock function with given fields: ctx, message diff --git a/pkg/database/plugin.go b/pkg/database/plugin.go index 3cb940730b..b1ead72b20 100644 --- a/pkg/database/plugin.go +++ b/pkg/database/plugin.go @@ -54,7 +54,7 @@ type Plugin interface { Init(ctx context.Context, config config.Section) error // RegisterListener registers a listener to receive callbacks - RegisterListener(callbacks Callbacks) + RegisterListener(listener Callbacks) // Capabilities returns capabilities - not called until after Init Capabilities() *Capabilities From dc1121539cf5d4b55dc332c9dc8c93b753239dff Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Thu, 9 Jun 2022 13:10:53 -0400 Subject: [PATCH 25/33] Tokens plugin can track multiple listeners Each listener will ignore events outside its namespace. Signed-off-by: Andrew Richardson --- internal/events/token_pool_created.go | 9 +++++ internal/events/token_pool_created_test.go | 6 +-- internal/events/tokens_approved.go | 4 ++ internal/events/tokens_transferred.go | 4 ++ internal/tokens/fftokens/fftokens.go | 43 ++++++++++++++++++++-- internal/tokens/fftokens/fftokens_test.go | 26 +++++-------- mocks/tokenmocks/plugin.go | 6 +-- pkg/tokens/plugin.go | 2 +- 8 files changed, 74 insertions(+), 26 deletions(-) diff --git a/internal/events/token_pool_created.go b/internal/events/token_pool_created.go index 449eea2714..a8c3346018 100644 --- a/internal/events/token_pool_created.go +++ b/internal/events/token_pool_created.go @@ -147,6 +147,10 @@ func (em *eventManager) TokenPoolCreated(ti tokens.Plugin, pool *tokens.TokenPoo return err } if existingPool != nil { + if existingPool.Namespace != em.namespace { + log.L(em.ctx).Debugf("Ignoring token pool from wrong namespace '%s'", existingPool.Namespace) + return nil + } if existingPool.State == core.TokenPoolStateConfirmed { return nil // already confirmed } @@ -163,6 +167,11 @@ func (em *eventManager) TokenPoolCreated(ti tokens.Plugin, pool *tokens.TokenPoo if announcePool, err = em.shouldAnnounce(ctx, pool); err != nil { return err } else if announcePool != nil { + if announcePool.Namespace != em.namespace { + log.L(em.ctx).Debugf("Ignoring token pool from wrong namespace '%s'", announcePool.Namespace) + announcePool = nil + return nil + } return nil // trigger announce after completion of database transaction } diff --git a/internal/events/token_pool_created_test.go b/internal/events/token_pool_created_test.go index e8eb242712..0526b1233d 100644 --- a/internal/events/token_pool_created_test.go +++ b/internal/events/token_pool_created_test.go @@ -427,7 +427,7 @@ func TestTokenPoolCreatedAnnounce(t *testing.T) { ID: fftypes.NewUUID(), Input: fftypes.JSONObject{ "id": poolID.String(), - "namespace": "test-ns", + "namespace": "ns1", "name": "my-pool", }, }, @@ -451,8 +451,8 @@ func TestTokenPoolCreatedAnnounce(t *testing.T) { mdi.On("GetTokenPoolByLocator", em.ctx, "erc1155", "123").Return(nil, nil).Times(2) mdi.On("GetOperations", em.ctx, mock.Anything).Return(nil, nil, fmt.Errorf("pop")).Once() mdi.On("GetOperations", em.ctx, mock.Anything).Return(operations, nil, nil).Once() - mbm.On("BroadcastTokenPool", em.ctx, "test-ns", mock.MatchedBy(func(pool *core.TokenPoolAnnouncement) bool { - return pool.Pool.Namespace == "test-ns" && pool.Pool.Name == "my-pool" && *pool.Pool.ID == *poolID + mbm.On("BroadcastTokenPool", em.ctx, "ns1", mock.MatchedBy(func(pool *core.TokenPoolAnnouncement) bool { + return pool.Pool.Namespace == "ns1" && pool.Pool.Name == "my-pool" && *pool.Pool.ID == *poolID }), false).Return(nil, nil) err := em.TokenPoolCreated(mti, pool) diff --git a/internal/events/tokens_approved.go b/internal/events/tokens_approved.go index 1e5eeef762..9e07ee89d0 100644 --- a/internal/events/tokens_approved.go +++ b/internal/events/tokens_approved.go @@ -78,6 +78,10 @@ func (em *eventManager) persistTokenApproval(ctx context.Context, approval *toke log.L(ctx).Infof("Token approval received for unknown pool '%s' - ignoring: %s", approval.PoolLocator, approval.Event.ProtocolID) return false, nil } + if pool.Namespace != em.namespace { + log.L(em.ctx).Debugf("Ignoring token approval from wrong namespace '%s'", pool.Namespace) + return false, nil + } approval.Namespace = pool.Namespace approval.Pool = pool.ID diff --git a/internal/events/tokens_transferred.go b/internal/events/tokens_transferred.go index 0206e87e3a..e819924b00 100644 --- a/internal/events/tokens_transferred.go +++ b/internal/events/tokens_transferred.go @@ -78,6 +78,10 @@ func (em *eventManager) persistTokenTransfer(ctx context.Context, transfer *toke log.L(ctx).Infof("Token transfer received for unknown pool '%s' - ignoring: %s", transfer.PoolLocator, transfer.Event.ProtocolID) return false, nil } + if pool.Namespace != em.namespace { + log.L(em.ctx).Debugf("Ignoring token transfer from wrong namespace '%s'", pool.Namespace) + return false, nil + } transfer.Namespace = pool.Namespace transfer.Pool = pool.ID diff --git a/internal/tokens/fftokens/fftokens.go b/internal/tokens/fftokens/fftokens.go index 1cd931f316..352f2f56f6 100644 --- a/internal/tokens/fftokens/fftokens.go +++ b/internal/tokens/fftokens/fftokens.go @@ -36,12 +36,49 @@ import ( type FFTokens struct { ctx context.Context capabilities *tokens.Capabilities - callbacks tokens.Callbacks + callbacks callbacks configuredName string client *resty.Client wsconn wsclient.WSClient } +type callbacks struct { + listeners []tokens.Callbacks +} + +func (cb *callbacks) TokenOpUpdate(plugin tokens.Plugin, nsOpID string, txState core.OpStatus, blockchainTXID, errorMessage string, opOutput fftypes.JSONObject) { + for _, cb := range cb.listeners { + cb.TokenOpUpdate(plugin, nsOpID, txState, blockchainTXID, errorMessage, opOutput) + } +} + +func (cb *callbacks) TokenPoolCreated(plugin tokens.Plugin, pool *tokens.TokenPool) error { + for _, cb := range cb.listeners { + if err := cb.TokenPoolCreated(plugin, pool); err != nil { + return err + } + } + return nil +} + +func (cb *callbacks) TokensTransferred(plugin tokens.Plugin, transfer *tokens.TokenTransfer) error { + for _, cb := range cb.listeners { + if err := cb.TokensTransferred(plugin, transfer); err != nil { + return err + } + } + return nil +} + +func (cb *callbacks) TokensApproved(plugin tokens.Plugin, approval *tokens.TokenApproval) error { + for _, cb := range cb.listeners { + if err := cb.TokensApproved(plugin, approval); err != nil { + return err + } + } + return nil +} + type wsEvent struct { Event msgType `json:"event"` ID string `json:"id"` @@ -159,8 +196,8 @@ func (ft *FFTokens) Init(ctx context.Context, name string, config config.Section return nil } -func (ft *FFTokens) RegisterListener(callbacks tokens.Callbacks) { - ft.callbacks = callbacks +func (ft *FFTokens) RegisterListener(listener tokens.Callbacks) { + ft.callbacks.listeners = append(ft.callbacks.listeners, listener) } func (ft *FFTokens) Start() error { diff --git a/internal/tokens/fftokens/fftokens_test.go b/internal/tokens/fftokens/fftokens_test.go index 6d6bcc18dd..38689c13c8 100644 --- a/internal/tokens/fftokens/fftokens_test.go +++ b/internal/tokens/fftokens/fftokens_test.go @@ -260,7 +260,7 @@ func TestCreateTokenPoolSynchronous(t *testing.T) { }) mcb := &tokenmocks.Callbacks{} - h.callbacks = mcb + h.RegisterListener(mcb) mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { return p.PoolLocator == "F1" && p.Type == core.TokenTypeFungible && *p.TX.ID == *pool.TX.ID })).Return(nil) @@ -414,7 +414,7 @@ func TestActivateTokenPoolSynchronous(t *testing.T) { }) mcb := &tokenmocks.Callbacks{} - h.callbacks = mcb + h.RegisterListener(mcb) mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { return p.PoolLocator == "F1" && p.Type == core.TokenTypeFungible && p.TX.ID == nil && p.Event.ProtocolID == "" })).Return(nil) @@ -460,7 +460,7 @@ func TestActivateTokenPoolSynchronousBadResponse(t *testing.T) { }) mcb := &tokenmocks.Callbacks{} - h.callbacks = mcb + h.RegisterListener(mcb) mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { return p.PoolLocator == "F1" && p.Type == core.TokenTypeFungible && p.TX.ID == nil })).Return(nil) @@ -780,7 +780,7 @@ func TestEvents(t *testing.T) { assert.Equal(t, `{"data":{"id":"1"},"event":"ack"}`, string(msg)) mcb := &tokenmocks.Callbacks{} - h.callbacks = mcb + h.RegisterListener(mcb) opID := fftypes.NewUUID() txID := fftypes.NewUUID() @@ -1118,12 +1118,10 @@ func TestEvents(t *testing.T) { } func TestEventLoopReceiveClosed(t *testing.T) { - dxc := &tokenmocks.Callbacks{} wsm := &wsmocks.WSClient{} h := &FFTokens{ - ctx: context.Background(), - callbacks: dxc, - wsconn: wsm, + ctx: context.Background(), + wsconn: wsm, } r := make(chan []byte) close(r) @@ -1133,12 +1131,10 @@ func TestEventLoopReceiveClosed(t *testing.T) { } func TestEventLoopSendClosed(t *testing.T) { - dxc := &tokenmocks.Callbacks{} wsm := &wsmocks.WSClient{} h := &FFTokens{ - ctx: context.Background(), - callbacks: dxc, - wsconn: wsm, + ctx: context.Background(), + wsconn: wsm, } r := make(chan []byte, 1) r <- []byte(`{"id":"1"}`) // ignored but acked @@ -1149,14 +1145,12 @@ func TestEventLoopSendClosed(t *testing.T) { } func TestEventLoopClosedContext(t *testing.T) { - dxc := &tokenmocks.Callbacks{} wsm := &wsmocks.WSClient{} ctx, cancel := context.WithCancel(context.Background()) cancel() h := &FFTokens{ - ctx: ctx, - callbacks: dxc, - wsconn: wsm, + ctx: ctx, + wsconn: wsm, } r := make(chan []byte, 1) wsm.On("Close").Return() diff --git a/mocks/tokenmocks/plugin.go b/mocks/tokenmocks/plugin.go index f389bf4924..a53733786e 100644 --- a/mocks/tokenmocks/plugin.go +++ b/mocks/tokenmocks/plugin.go @@ -138,9 +138,9 @@ func (_m *Plugin) Name() string { return r0 } -// RegisterListener provides a mock function with given fields: callbacks -func (_m *Plugin) RegisterListener(callbacks tokens.Callbacks) { - _m.Called(callbacks) +// RegisterListener provides a mock function with given fields: listener +func (_m *Plugin) RegisterListener(listener tokens.Callbacks) { + _m.Called(listener) } // Start provides a mock function with given fields: diff --git a/pkg/tokens/plugin.go b/pkg/tokens/plugin.go index 1ca4e922d8..0363da50ed 100644 --- a/pkg/tokens/plugin.go +++ b/pkg/tokens/plugin.go @@ -36,7 +36,7 @@ type Plugin interface { Init(ctx context.Context, name string, config config.Section) error // RegisterListener registers a listener to receive callbacks - RegisterListener(callbacks Callbacks) + RegisterListener(listener Callbacks) // Blockchain interface must not deliver any events until start is called Start() error From e19f2a470ccd951a8242ff556ba4eeb6d1cefaa0 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Thu, 9 Jun 2022 14:40:29 -0400 Subject: [PATCH 26/33] Tweak namespace parsing from dx Signed-off-by: Andrew Richardson --- internal/dataexchange/ffdx/dxevent.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/dataexchange/ffdx/dxevent.go b/internal/dataexchange/ffdx/dxevent.go index b125fe7b26..304ad4aa3e 100644 --- a/internal/dataexchange/ffdx/dxevent.go +++ b/internal/dataexchange/ffdx/dxevent.go @@ -156,10 +156,14 @@ func (h *FFDX) dispatchEvent(msg *wsEvent) { var hash *fftypes.Bytes32 hash, err = fftypes.ParseBytes32(h.ctx, msg.Hash) if err == nil { + var ns string pathParts := strings.Split(msg.Path, "/") + if len(pathParts) >= 2 { + ns = pathParts[len(pathParts)-2] + } e.dxType = dataexchange.DXEventTypePrivateBlobReceived e.privateBlobReceived = &dataexchange.PrivateBlobReceived{ - Namespace: pathParts[0], + Namespace: ns, PeerID: msg.Sender, Hash: *hash, Size: msg.Size, From 6e9cce60bcac029a9f018075daf2671afb07fc78 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Thu, 9 Jun 2022 15:10:05 -0400 Subject: [PATCH 27/33] Add remaining test coverage Signed-off-by: Andrew Richardson --- internal/blockchain/ethereum/ethereum_test.go | 48 +++++- internal/blockchain/fabric/fabric_test.go | 38 +++++ internal/database/postgres/postgres_test.go | 2 + internal/database/sqlite3/sqlite3_test.go | 2 + internal/events/batch_pin_complete.go | 8 +- internal/events/batch_pin_complete_test.go | 20 +++ internal/events/blockchain_event_test.go | 32 ++++ internal/events/dx_callbacks_test.go | 33 ++++ internal/events/token_pool_created_test.go | 99 +++++++++++ internal/events/tokens_approved_test.go | 21 +++ internal/events/tokens_transferred_test.go | 21 +++ internal/namespace/manager_test.go | 154 +++++++++++++++--- internal/operations/operation_updater_test.go | 10 ++ internal/orchestrator/orchestrator.go | 5 - internal/orchestrator/orchestrator_test.go | 34 ++-- .../orchestrator/persistence_events_test.go | 25 +++ internal/tokens/fftokens/fftokens_test.go | 140 ++++++++++++++-- 17 files changed, 635 insertions(+), 57 deletions(-) diff --git a/internal/blockchain/ethereum/ethereum_test.go b/internal/blockchain/ethereum/ethereum_test.go index 5196f0bffd..d766df1811 100644 --- a/internal/blockchain/ethereum/ethereum_test.go +++ b/internal/blockchain/ethereum/ethereum_test.go @@ -1573,7 +1573,7 @@ func TestHandleBadPayloadsAndThenReceiptFailure(t *testing.T) { }`) em := &blockchainmocks.Callbacks{} - e.callbacks.listeners = []blockchain.Callbacks{em} + e.RegisterListener(em) txsu := em.On("BlockchainOpUpdate", e, "ns1:"+operationID.String(), @@ -2983,6 +2983,52 @@ func TestHandleNetworkAction(t *testing.T) { } +func TestHandleNetworkActionFail(t *testing.T) { + data := fftypes.JSONAnyPtr(` +[ + { + "address": "0x1C197604587F046FD40684A8f21f4609FB811A7b", + "blockNumber": "38011", + "transactionIndex": "0x0", + "transactionHash": "0xc26df2bf1a733e9249372d61eb11bd8662d26c8129df76890b1beb2f6fa72628", + "data": { + "author": "0X91D2B4381A4CD5C7C0F27565A7D4B829844C8635", + "namespace": "firefly:terminate", + "uuids": "0x0000000000000000000000000000000000000000000000000000000000000000", + "batchHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "payloadRef": "", + "contexts": [] + }, + "subId": "sb-b5b97a4e-a317-4053-6400-1474650efcb5", + "signature": "BatchPin(address,uint256,string,bytes32,bytes32,string,bytes32[])", + "logIndex": "50", + "timestamp": "1620576488" + } +]`) + + em := &blockchainmocks.Callbacks{} + e := &Ethereum{ + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, + } + e.fireflyContract.subscription = "sb-b5b97a4e-a317-4053-6400-1474650efcb5" + + expectedSigningKeyRef := &core.VerifierRef{ + Type: core.VerifierTypeEthAddress, + Value: "0x91d2b4381a4cd5c7c0f27565a7d4b829844c8635", + } + + em.On("BlockchainNetworkAction", "terminate", mock.Anything, expectedSigningKeyRef).Return(fmt.Errorf("pop")) + + var events []interface{} + err := json.Unmarshal(data.Bytes(), &events) + assert.NoError(t, err) + err = e.handleMessageBatch(context.Background(), events) + assert.EqualError(t, err, "pop") + + em.AssertExpectations(t) + +} + func TestNetworkVersion(t *testing.T) { e, _ := newTestEthereum() e.fireflyContract.networkVersion = 2 diff --git a/internal/blockchain/fabric/fabric_test.go b/internal/blockchain/fabric/fabric_test.go index 110df20803..e8ea554b67 100644 --- a/internal/blockchain/fabric/fabric_test.go +++ b/internal/blockchain/fabric/fabric_test.go @@ -2051,6 +2051,44 @@ func TestHandleNetworkAction(t *testing.T) { } +func TestHandleNetworkActionFail(t *testing.T) { + data := []byte(` +[ + { + "chaincodeId": "firefly", + "blockNumber": 91, + "transactionId": "ce79343000e851a0c742f63a733ce19a5f8b9ce1c719b6cecd14f01bcf81fff2", + "transactionIndex": 2, + "eventIndex": 50, + "eventName": "BatchPin", + "payload": "eyJzaWduZXIiOiJ1MHZnd3U5czAwLXg1MDk6OkNOPXVzZXIyLE9VPWNsaWVudDo6Q049ZmFicmljLWNhLXNlcnZlciIsInRpbWVzdGFtcCI6eyJzZWNvbmRzIjoxNjMwMDMxNjY3LCJuYW5vcyI6NzkxNDk5MDAwfSwibmFtZXNwYWNlIjoiZmlyZWZseTp0ZXJtaW5hdGUiLCJ1dWlkcyI6IjB4MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCIsImJhdGNoSGFzaCI6IjB4MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCIsInBheWxvYWRSZWYiOiIiLCJjb250ZXh0cyI6W119", + "subId": "sb-0910f6a8-7bd6-4ced-453e-2db68149ce8e" + } +]`) + + em := &blockchainmocks.Callbacks{} + e := &Fabric{ + callbacks: callbacks{listeners: []blockchain.Callbacks{em}}, + } + e.fireflyContract.subscription = "sb-0910f6a8-7bd6-4ced-453e-2db68149ce8e" + + expectedSigningKeyRef := &core.VerifierRef{ + Type: core.VerifierTypeMSPIdentity, + Value: "u0vgwu9s00-x509::CN=user2,OU=client::CN=fabric-ca-server", + } + + em.On("BlockchainNetworkAction", "terminate", mock.Anything, expectedSigningKeyRef).Return(fmt.Errorf("pop")) + + var events []interface{} + err := json.Unmarshal(data, &events) + assert.NoError(t, err) + err = e.handleMessageBatch(context.Background(), events) + assert.EqualError(t, err, "pop") + + em.AssertExpectations(t) + +} + func TestNetworkVersion(t *testing.T) { e, _ := newTestFabric() e.fireflyContract.networkVersion = 2 diff --git a/internal/database/postgres/postgres_test.go b/internal/database/postgres/postgres_test.go index b1a41a8143..ffc78365fb 100644 --- a/internal/database/postgres/postgres_test.go +++ b/internal/database/postgres/postgres_test.go @@ -23,11 +23,13 @@ import ( sq "github.com/Masterminds/squirrel" "github.com/hyperledger/firefly-common/pkg/config" "github.com/hyperledger/firefly/internal/database/sqlcommon" + "github.com/hyperledger/firefly/mocks/databasemocks" "github.com/stretchr/testify/assert" ) func TestPostgresProvider(t *testing.T) { psql := &Postgres{} + psql.RegisterListener(&databasemocks.Callbacks{}) config := config.RootSection("unittest") psql.InitConfig(config) config.Set(sqlcommon.SQLConfDatasourceURL, "!bad connection") diff --git a/internal/database/sqlite3/sqlite3_test.go b/internal/database/sqlite3/sqlite3_test.go index 8c4cdc5716..78e5aa0a05 100644 --- a/internal/database/sqlite3/sqlite3_test.go +++ b/internal/database/sqlite3/sqlite3_test.go @@ -26,11 +26,13 @@ import ( sq "github.com/Masterminds/squirrel" "github.com/hyperledger/firefly-common/pkg/config" "github.com/hyperledger/firefly/internal/database/sqlcommon" + "github.com/hyperledger/firefly/mocks/databasemocks" "github.com/stretchr/testify/assert" ) func TestSQLite3GoProvider(t *testing.T) { sqlite := &SQLite3{} + sqlite.RegisterListener(&databasemocks.Callbacks{}) config := config.RootSection("unittest") sqlite.InitConfig(config) config.Set(sqlcommon.SQLConfDatasourceURL, "!wrong://") diff --git a/internal/events/batch_pin_complete.go b/internal/events/batch_pin_complete.go index 53aa1ece82..2903219a2c 100644 --- a/internal/events/batch_pin_complete.go +++ b/internal/events/batch_pin_complete.go @@ -32,10 +32,6 @@ import ( // We must block here long enough to get the payload from the sharedstorage, persist the messages in the correct // sequence, and also persist all the data. func (em *eventManager) BatchPinComplete(bi blockchain.Plugin, batchPin *blockchain.BatchPin, signingKey *core.VerifierRef) error { - if batchPin.Namespace != em.namespace { - log.L(em.ctx).Debugf("Ignoring BatchPin from wrong namespace '%s'", batchPin.Namespace) - return nil // move on - } if batchPin.TransactionID == nil { log.L(em.ctx).Errorf("Invalid BatchPin transaction - ID is nil") return nil // move on @@ -44,6 +40,10 @@ func (em *eventManager) BatchPinComplete(bi blockchain.Plugin, batchPin *blockch log.L(em.ctx).Errorf("Invalid transaction ID='%s' - invalid namespace '%s': %a", batchPin.TransactionID, batchPin.Namespace, err) return nil // move on } + if batchPin.Namespace != em.namespace { + log.L(em.ctx).Debugf("Ignoring BatchPin from wrong namespace '%s'", batchPin.Namespace) + return nil // move on + } log.L(em.ctx).Infof("-> BatchPinComplete batch=%s txn=%s signingIdentity=%s", batchPin.BatchID, batchPin.Event.ProtocolID, signingKey.Value) defer func() { diff --git a/internal/events/batch_pin_complete_test.go b/internal/events/batch_pin_complete_test.go index 6b19e6743c..be4fae9614 100644 --- a/internal/events/batch_pin_complete_test.go +++ b/internal/events/batch_pin_complete_test.go @@ -414,6 +414,26 @@ func TestBatchPinCompleteBadNamespace(t *testing.T) { assert.NoError(t, err) } +func TestBatchPinCompleteWrongNamespace(t *testing.T) { + em, cancel := newTestEventManager(t) + defer cancel() + + batch := &blockchain.BatchPin{ + Namespace: "ns2", + TransactionID: fftypes.NewUUID(), + Event: blockchain.Event{ + BlockchainTXID: "0x12345", + }, + } + mbi := &blockchainmocks.Plugin{} + + err := em.BatchPinComplete(mbi, batch, &core.VerifierRef{ + Type: core.VerifierTypeEthAddress, + Value: "0x12345", + }) + assert.NoError(t, err) +} + func TestPersistBatchMissingID(t *testing.T) { em, cancel := newTestEventManager(t) defer cancel() diff --git a/internal/events/blockchain_event_test.go b/internal/events/blockchain_event_test.go index 5c1ec86b9d..c48f13c621 100644 --- a/internal/events/blockchain_event_test.go +++ b/internal/events/blockchain_event_test.go @@ -105,6 +105,38 @@ func TestContractEventUnknownSubscription(t *testing.T) { mdi.AssertExpectations(t) } +func TestContractEventWrongNS(t *testing.T) { + em, cancel := newTestEventManager(t) + defer cancel() + + ev := &blockchain.EventWithSubscription{ + Subscription: "sb-1", + Event: blockchain.Event{ + BlockchainTXID: "0xabcd1234", + Name: "Changed", + Output: fftypes.JSONObject{ + "value": "1", + }, + Info: fftypes.JSONObject{ + "blockNumber": "10", + }, + }, + } + sub := &core.ContractListener{ + Namespace: "ns2", + ID: fftypes.NewUUID(), + Topic: "topic1", + } + + mdi := em.database.(*databasemocks.Plugin) + mdi.On("GetContractListenerByBackendID", mock.Anything, "sb-1").Return(sub, nil) + + err := em.BlockchainEvent(ev) + assert.NoError(t, err) + + mdi.AssertExpectations(t) +} + func TestPersistBlockchainEventDuplicate(t *testing.T) { em, cancel := newTestEventManager(t) defer cancel() diff --git a/internal/events/dx_callbacks_test.go b/internal/events/dx_callbacks_test.go index a24840d86a..2e7e8e13a1 100644 --- a/internal/events/dx_callbacks_test.go +++ b/internal/events/dx_callbacks_test.go @@ -297,6 +297,23 @@ func TestMessageReceivedNilMessage(t *testing.T) { mde.AssertExpectations(t) } +func TestMessageReceivedWrongNS(t *testing.T) { + em, cancel := newTestEventManager(t) + defer cancel() + em.namespace = "ns2" + + _, b := sampleBatchTransfer(t, core.TransactionTypeBatchPin) + + mdx := &dataexchangemocks.Plugin{} + mdx.On("Name").Return("utdx") + + mde := newMessageReceivedNoAck("peer1", b) + em.messageReceived(mdx, mde) + + mde.AssertExpectations(t) + +} + func TestMessageReceivedNilGroup(t *testing.T) { em, cancel := newTestEventManager(t) defer cancel() @@ -497,6 +514,22 @@ func TestPrivateBlobReceivedGetBlobsFails(t *testing.T) { mdi.AssertExpectations(t) } +func TestPrivateBlobReceivedWrongNS(t *testing.T) { + em, cancel := newTestEventManager(t) + cancel() // retryable error + em.namespace = "ns2" + hash := fftypes.NewRandB32() + + mdx := &dataexchangemocks.Plugin{} + mdx.On("Name").Return("utdx") + + // no ack as we are simulating termination mid retry + mde := newPrivateBlobReceivedNoAck("peer1", hash, 12345, "ns1/path1") + em.privateBlobReceived(mdx, mde) + + mde.AssertExpectations(t) +} + func TestMessageReceiveMessageIdentityFail(t *testing.T) { em, cancel := newTestEventManager(t) cancel() // to avoid infinite retry diff --git a/internal/events/token_pool_created_test.go b/internal/events/token_pool_created_test.go index 0526b1233d..b468291410 100644 --- a/internal/events/token_pool_created_test.go +++ b/internal/events/token_pool_created_test.go @@ -157,6 +157,60 @@ func TestTokenPoolCreatedConfirm(t *testing.T) { mdm.AssertExpectations(t) } +func TestTokenPoolCreatedConfirmWrongNS(t *testing.T) { + em, cancel := newTestEventManager(t) + defer cancel() + mdi := em.database.(*databasemocks.Plugin) + mti := &tokenmocks.Plugin{} + mth := em.txHelper.(*txcommonmocks.Helper) + mdm := em.data.(*datamocks.Manager) + + txID := fftypes.NewUUID() + info1 := fftypes.JSONObject{"pool": "info"} + info2 := fftypes.JSONObject{"block": "info"} + chainPool := &tokens.TokenPool{ + Type: core.TokenTypeFungible, + PoolLocator: "123", + Connector: "erc1155", + TX: core.TransactionRef{ + ID: txID, + Type: core.TransactionTypeTokenPool, + }, + Standard: "ERC1155", + Symbol: "FFT", + Info: info1, + Event: blockchain.Event{ + BlockchainTXID: "0xffffeeee", + Name: "TokenPool", + ProtocolID: "tx1", + Info: info2, + }, + } + storedPool := &core.TokenPool{ + Namespace: "ns2", + ID: fftypes.NewUUID(), + State: core.TokenPoolStatePending, + Message: fftypes.NewUUID(), + TX: core.TransactionRef{ + Type: core.TransactionTypeTokenPool, + ID: txID, + }, + } + + mdi.On("GetTokenPoolByLocator", em.ctx, "erc1155", "123").Return(nil, fmt.Errorf("pop")).Once() + mdi.On("GetTokenPoolByLocator", em.ctx, "erc1155", "123").Return(storedPool, nil).Once() + mth.On("InsertBlockchainEvent", em.ctx, mock.MatchedBy(func(e *core.BlockchainEvent) bool { + return e.Name == chainPool.Event.Name + })).Return(nil).Once() + mth.On("PersistTransaction", mock.Anything, "ns1", txID, core.TransactionTypeTokenPool, "0xffffeeee").Return(true, nil).Once() + + err := em.TokenPoolCreated(mti, chainPool) + assert.NoError(t, err) + + mdi.AssertExpectations(t) + mdm.AssertExpectations(t) +} + func TestTokenPoolCreatedAlreadyConfirmed(t *testing.T) { em, cancel := newTestEventManager(t) defer cancel() @@ -463,6 +517,51 @@ func TestTokenPoolCreatedAnnounce(t *testing.T) { mbm.AssertExpectations(t) } +func TestTokenPoolCreatedAnnounceWrongNS(t *testing.T) { + em, cancel := newTestEventManager(t) + defer cancel() + mdi := em.database.(*databasemocks.Plugin) + mti := &tokenmocks.Plugin{} + + poolID := fftypes.NewUUID() + txID := fftypes.NewUUID() + operations := []*core.Operation{ + { + ID: fftypes.NewUUID(), + Input: fftypes.JSONObject{ + "id": poolID.String(), + "namespace": "ns2", + "name": "my-pool", + }, + }, + } + info := fftypes.JSONObject{"some": "info"} + pool := &tokens.TokenPool{ + Type: core.TokenTypeFungible, + PoolLocator: "123", + TX: core.TransactionRef{ + ID: txID, + Type: core.TransactionTypeTokenPool, + }, + Connector: "erc1155", + Event: blockchain.Event{ + BlockchainTXID: "0xffffeeee", + ProtocolID: "tx1", + Info: info, + }, + } + + mdi.On("GetTokenPoolByLocator", em.ctx, "erc1155", "123").Return(nil, nil).Times(2) + mdi.On("GetOperations", em.ctx, mock.Anything).Return(nil, nil, fmt.Errorf("pop")).Once() + mdi.On("GetOperations", em.ctx, mock.Anything).Return(operations, nil, nil).Once() + + err := em.TokenPoolCreated(mti, pool) + assert.NoError(t, err) + + mti.AssertExpectations(t) + mdi.AssertExpectations(t) +} + func TestTokenPoolCreatedAnnounceBadOpInputID(t *testing.T) { em, cancel := newTestEventManager(t) defer cancel() diff --git a/internal/events/tokens_approved_test.go b/internal/events/tokens_approved_test.go index 921c3efbe4..d999e3383b 100644 --- a/internal/events/tokens_approved_test.go +++ b/internal/events/tokens_approved_test.go @@ -123,6 +123,27 @@ func TestPersistApprovalDuplicate(t *testing.T) { mdi.AssertExpectations(t) } +func TestPersistApprovalWrongNS(t *testing.T) { + em, cancel := newTestEventManager(t) + defer cancel() + + mdi := em.database.(*databasemocks.Plugin) + + approval := newApproval() + pool := &core.TokenPool{ + ID: fftypes.NewUUID(), + Namespace: "ns2", + } + + mdi.On("GetTokenPoolByLocator", em.ctx, "erc1155", "F1").Return(pool, nil) + + valid, err := em.persistTokenApproval(em.ctx, approval) + assert.False(t, valid) + assert.NoError(t, err) + + mdi.AssertExpectations(t) +} + func TestPersistApprovalOpFail(t *testing.T) { em, cancel := newTestEventManager(t) defer cancel() diff --git a/internal/events/tokens_transferred_test.go b/internal/events/tokens_transferred_test.go index 4b182da5cf..53988f404f 100644 --- a/internal/events/tokens_transferred_test.go +++ b/internal/events/tokens_transferred_test.go @@ -123,6 +123,27 @@ func TestTokensTransferredIgnoreExisting(t *testing.T) { mti.AssertExpectations(t) } +func TestPersistTransferWrongNS(t *testing.T) { + em, cancel := newTestEventManager(t) + defer cancel() + + mdi := em.database.(*databasemocks.Plugin) + + transfer := newTransfer() + pool := &core.TokenPool{ + ID: fftypes.NewUUID(), + Namespace: "ns2", + } + + mdi.On("GetTokenPoolByLocator", em.ctx, "erc1155", "F1").Return(pool, nil) + + valid, err := em.persistTokenTransfer(em.ctx, transfer) + assert.False(t, valid) + assert.NoError(t, err) + + mdi.AssertExpectations(t) +} + func TestPersistTransferOpFail(t *testing.T) { em, cancel := newTestEventManager(t) defer cancel() diff --git a/internal/namespace/manager_test.go b/internal/namespace/manager_test.go index 2b3391c800..d71cdca4fa 100644 --- a/internal/namespace/manager_test.go +++ b/internal/namespace/manager_test.go @@ -84,6 +84,7 @@ func newTestNamespaceManager(resetConfig bool) *testNamespaceManager { mps: &sharedstoragemocks.Plugin{}, mti: &tokenmocks.Plugin{}, namespaceManager: namespaceManager{ + ctx: context.Background(), namespaces: make(map[string]*namespace), pluginNames: make(map[string]bool), }, @@ -138,6 +139,105 @@ func TestInit(t *testing.T) { assert.Equal(t, mo, nm.Orchestrator("default")) assert.Nil(t, nm.Orchestrator("unknown")) + + mo.AssertExpectations(t) +} + +func TestInitDatabaseFail(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + nm.utOrchestrator = &orchestratormocks.Orchestrator{} + + nm.mdi.On("Init", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.EqualError(t, err, "pop") +} + +func TestInitBlockchainFail(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + nm.utOrchestrator = &orchestratormocks.Orchestrator{} + + nm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mdi.On("RegisterListener", mock.Anything).Return() + nm.mbi.On("Init", mock.Anything, mock.Anything, nm.mmi).Return(fmt.Errorf("pop")) + + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.EqualError(t, err, "pop") +} + +func TestInitDataExchangeFail(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + nm.utOrchestrator = &orchestratormocks.Orchestrator{} + + nm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mdi.On("RegisterListener", mock.Anything).Return() + nm.mbi.On("Init", mock.Anything, mock.Anything, nm.mmi).Return(nil) + nm.mdx.On("Init", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.EqualError(t, err, "pop") +} + +func TestInitSharedStorageFail(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + nm.utOrchestrator = &orchestratormocks.Orchestrator{} + + nm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mdi.On("RegisterListener", mock.Anything).Return() + nm.mbi.On("Init", mock.Anything, mock.Anything, nm.mmi).Return(nil) + nm.mdx.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mps.On("Init", mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.EqualError(t, err, "pop") +} + +func TestInitTokensFail(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + nm.utOrchestrator = &orchestratormocks.Orchestrator{} + + nm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mdi.On("RegisterListener", mock.Anything).Return() + nm.mbi.On("Init", mock.Anything, mock.Anything, nm.mmi).Return(nil) + nm.mdx.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mps.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mti.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("pop")) + + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.EqualError(t, err, "pop") +} + +func TestInitOrchestratorFail(t *testing.T) { + nm := newTestNamespaceManager(true) + defer nm.cleanup(t) + + nm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mdi.On("RegisterListener", mock.Anything).Return() + nm.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("pop")) + nm.mbi.On("Init", mock.Anything, mock.Anything, nm.mmi).Return(nil) + nm.mbi.On("RegisterListener", mock.Anything).Return() + nm.mdx.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mps.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mti.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + + ctx, cancelCtx := context.WithCancel(context.Background()) + err := nm.Init(ctx, cancelCtx) + assert.EqualError(t, err, "pop") } func TestInitVersion1(t *testing.T) { @@ -164,6 +264,8 @@ func TestInitVersion1(t *testing.T) { assert.Equal(t, mo, nm.Orchestrator("default")) assert.Nil(t, nm.Orchestrator("unknown")) assert.NotNil(t, nm.Orchestrator(core.LegacySystemNamespace)) + + mo.AssertExpectations(t) } func TestInitVersion1Fail(t *testing.T) { @@ -186,6 +288,8 @@ func TestInitVersion1Fail(t *testing.T) { ctx, cancelCtx := context.WithCancel(context.Background()) err := nm.Init(ctx, cancelCtx) assert.EqualError(t, err, "pop") + + mo.AssertExpectations(t) } func TestDeprecatedDatabasePlugin(t *testing.T) { @@ -542,10 +646,19 @@ func TestTokensPluginDuplicate(t *testing.T) { assert.Regexp(t, "FF10395", err) } -func TestInitNamespacesBadName(t *testing.T) { +func TestInitBadNamespace(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) + nm.utOrchestrator = &orchestratormocks.Orchestrator{} + + nm.mdi.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mdi.On("RegisterListener", mock.Anything).Return() + nm.mbi.On("Init", mock.Anything, mock.Anything, nm.mmi).Return(nil) + nm.mdx.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mps.On("Init", mock.Anything, mock.Anything).Return(nil) + nm.mti.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil) + viper.SetConfigType("yaml") err := viper.ReadConfig(strings.NewReader(` namespaces: @@ -555,11 +668,12 @@ func TestInitNamespacesBadName(t *testing.T) { `)) assert.NoError(t, err) - err = nm.loadNamespaces(context.Background()) + ctx, cancelCtx := context.WithCancel(context.Background()) + err = nm.Init(ctx, cancelCtx) assert.Regexp(t, "FF00140", err) } -func TestInitNamespacesReservedName(t *testing.T) { +func TestLoadNamespacesReservedName(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -576,7 +690,7 @@ func TestInitNamespacesReservedName(t *testing.T) { assert.Regexp(t, "FF10388", err) } -func TestInitNamespacesDuplicate(t *testing.T) { +func TestLoadNamespacesDuplicate(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -597,7 +711,7 @@ func TestInitNamespacesDuplicate(t *testing.T) { assert.Len(t, nm.namespaces, 1) } -func TestInitNamespacesNoName(t *testing.T) { +func TestLoadNamespacesNoName(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -613,7 +727,7 @@ func TestInitNamespacesNoName(t *testing.T) { assert.Regexp(t, "FF10166", err) } -func TestInitNamespacesNoDefault(t *testing.T) { +func TestLoadNamespacesNoDefault(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -631,7 +745,7 @@ func TestInitNamespacesNoDefault(t *testing.T) { assert.Regexp(t, "FF10166", err) } -func TestInitNamespacesUseDefaults(t *testing.T) { +func TestLoadNamespacesUseDefaults(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -651,7 +765,7 @@ func TestInitNamespacesUseDefaults(t *testing.T) { assert.Len(t, nm.namespaces, 1) } -func TestInitNamespacesGatewayNoDatabase(t *testing.T) { +func TestLoadNamespacesGatewayNoDatabase(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -669,7 +783,7 @@ func TestInitNamespacesGatewayNoDatabase(t *testing.T) { assert.Regexp(t, "FF10392", err) } -func TestInitNamespacesMultipartyUnknownPlugin(t *testing.T) { +func TestLoadNamespacesMultipartyUnknownPlugin(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -689,7 +803,7 @@ func TestInitNamespacesMultipartyUnknownPlugin(t *testing.T) { assert.Regexp(t, "FF10390.*unknown", err) } -func TestInitNamespacesMultipartyMultipleBlockchains(t *testing.T) { +func TestLoadNamespacesMultipartyMultipleBlockchains(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -709,7 +823,7 @@ func TestInitNamespacesMultipartyMultipleBlockchains(t *testing.T) { assert.Regexp(t, "FF10394.*blockchain", err) } -func TestInitNamespacesMultipartyMultipleDX(t *testing.T) { +func TestLoadNamespacesMultipartyMultipleDX(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -729,7 +843,7 @@ func TestInitNamespacesMultipartyMultipleDX(t *testing.T) { assert.Regexp(t, "FF10394.*dataexchange", err) } -func TestInitNamespacesMultipartyMultipleSS(t *testing.T) { +func TestLoadNamespacesMultipartyMultipleSS(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -749,7 +863,7 @@ func TestInitNamespacesMultipartyMultipleSS(t *testing.T) { assert.Regexp(t, "FF10394.*sharedstorage", err) } -func TestInitNamespacesMultipartyMultipleDB(t *testing.T) { +func TestLoadNamespacesMultipartyMultipleDB(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -769,7 +883,7 @@ func TestInitNamespacesMultipartyMultipleDB(t *testing.T) { assert.Regexp(t, "FF10394.*database", err) } -func TestInitNamespacesGatewayMultipleDB(t *testing.T) { +func TestLoadNamespacesGatewayMultipleDB(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -787,7 +901,7 @@ func TestInitNamespacesGatewayMultipleDB(t *testing.T) { assert.Regexp(t, "FF10394.*database", err) } -func TestInitNamespacesGatewayMultipleBlockchains(t *testing.T) { +func TestLoadNamespacesGatewayMultipleBlockchains(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -805,7 +919,7 @@ func TestInitNamespacesGatewayMultipleBlockchains(t *testing.T) { assert.Regexp(t, "FF10394.*blockchain", err) } -func TestInitNamespacesMultipartyMissingPlugins(t *testing.T) { +func TestLoadNamespacesMultipartyMissingPlugins(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -825,7 +939,7 @@ func TestInitNamespacesMultipartyMissingPlugins(t *testing.T) { assert.Regexp(t, "FF10391", err) } -func TestInitNamespacesGatewayWithDX(t *testing.T) { +func TestLoadNamespacesGatewayWithDX(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -843,7 +957,7 @@ func TestInitNamespacesGatewayWithDX(t *testing.T) { assert.Regexp(t, "FF10393", err) } -func TestInitNamespacesGatewayWithSharedStorage(t *testing.T) { +func TestLoadNamespacesGatewayWithSharedStorage(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -861,7 +975,7 @@ func TestInitNamespacesGatewayWithSharedStorage(t *testing.T) { assert.Regexp(t, "FF10393", err) } -func TestInitNamespacesGatewayUnknownPlugin(t *testing.T) { +func TestLoadNamespacesGatewayUnknownPlugin(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) @@ -879,7 +993,7 @@ func TestInitNamespacesGatewayUnknownPlugin(t *testing.T) { assert.Regexp(t, "FF10390.*unknown", err) } -func TestInitNamespacesGatewayTokens(t *testing.T) { +func TestLoadNamespacesGatewayTokens(t *testing.T) { nm := newTestNamespaceManager(true) defer nm.cleanup(t) diff --git a/internal/operations/operation_updater_test.go b/internal/operations/operation_updater_test.go index d99e2c5a9e..ef51220e09 100644 --- a/internal/operations/operation_updater_test.go +++ b/internal/operations/operation_updater_test.go @@ -115,6 +115,16 @@ func TestSubmitUpdateSyncFallbackOpNotFound(t *testing.T) { mdi.AssertExpectations(t) } +func TestSubmitUpdateWrongNS(t *testing.T) { + ou := newTestOperationUpdaterNoConcurrency(t) + defer ou.close() + customCtx := context.WithValue(context.Background(), "dbtx", "on this context") + + ou.SubmitOperationUpdate(customCtx, &OperationUpdate{ + NamespacedOpID: "ns2:" + fftypes.NewUUID().String(), + }) +} + func TestSubmitUpdateWorkerE2ESuccess(t *testing.T) { om, cancel := newTestOperations(t) defer om.WaitStop() diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index aed19cefcd..f1c6367dfd 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -59,7 +59,6 @@ type Orchestrator interface { Contracts() contracts.Manager Data() data.Manager Events() events.EventManager - Metrics() metrics.Manager NetworkMap() networkmap.Manager Operations() operations.Manager PrivateMessaging() privatemessaging.Manager @@ -350,10 +349,6 @@ func (or *orchestrator) Contracts() contracts.Manager { return or.contracts } -func (or *orchestrator) Metrics() metrics.Manager { - return or.metrics -} - func (or *orchestrator) Operations() operations.Manager { return or.operations } diff --git a/internal/orchestrator/orchestrator_test.go b/internal/orchestrator/orchestrator_test.go index d85541e45c..9d6411fabb 100644 --- a/internal/orchestrator/orchestrator_test.go +++ b/internal/orchestrator/orchestrator_test.go @@ -182,18 +182,7 @@ func TestNewOrchestrator(t *testing.T) { assert.NotNil(t, or) } -func TestInitPluginsDataexchangeNodesFail(t *testing.T) { - or := newTestOrchestrator() - defer or.cleanup(t) - or.mdi.On("RegisterListener", mock.Anything).Return() - or.mbi.On("RegisterListener", mock.Anything).Return() - or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("pop")) - ctx := context.Background() - err := or.initPlugins(ctx) - assert.EqualError(t, err, "pop") -} - -func TestInitAllPluginsOK(t *testing.T) { +func TestInitOK(t *testing.T) { or := newTestOrchestrator() defer or.cleanup(t) or.mdi.On("RegisterListener", mock.Anything).Return() @@ -205,6 +194,27 @@ func TestInitAllPluginsOK(t *testing.T) { or.mti.On("RegisterListener", mock.Anything).Return() err := or.Init(or.ctx, or.cancelCtx) assert.NoError(t, err) + + assert.Equal(t, or.mba, or.BatchManager()) + assert.Equal(t, or.mbm, or.Broadcast()) + assert.Equal(t, or.mpm, or.PrivateMessaging()) + assert.Equal(t, or.mem, or.Events()) + assert.Equal(t, or.mam, or.Assets()) + assert.Equal(t, or.mdm, or.Data()) + assert.Equal(t, or.mom, or.Operations()) + assert.Equal(t, or.mcm, or.Contracts()) + assert.Equal(t, or.mnm, or.NetworkMap()) +} + +func TestInitDataexchangeNodesFail(t *testing.T) { + or := newTestOrchestrator() + defer or.cleanup(t) + or.mdi.On("RegisterListener", mock.Anything).Return() + or.mbi.On("RegisterListener", mock.Anything).Return() + or.mdi.On("GetIdentities", mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("pop")) + ctx := context.Background() + err := or.initPlugins(ctx) + assert.EqualError(t, err, "pop") } func TestInitMessagingComponentFail(t *testing.T) { diff --git a/internal/orchestrator/persistence_events_test.go b/internal/orchestrator/persistence_events_test.go index e78d7e6e1f..6b34d743c6 100644 --- a/internal/orchestrator/persistence_events_test.go +++ b/internal/orchestrator/persistence_events_test.go @@ -17,6 +17,7 @@ package orchestrator import ( + "context" "testing" "github.com/hyperledger/firefly-common/pkg/fftypes" @@ -91,3 +92,27 @@ func TestSubscriptionDeleted(t *testing.T) { o.UUIDCollectionNSEvent(database.CollectionSubscriptions, core.ChangeEventTypeDeleted, "ns1", fftypes.NewUUID()) mem.AssertExpectations(t) } + +func TestOrderedUUIDCollectionWrongNS(t *testing.T) { + o := &orchestrator{ + ctx: context.Background(), + namespace: "ns1", + } + o.OrderedUUIDCollectionNSEvent(database.CollectionMessages, core.ChangeEventTypeCreated, "ns2", fftypes.NewUUID(), 1) +} + +func TestOrderedCollectionWrongNS(t *testing.T) { + o := &orchestrator{ + ctx: context.Background(), + namespace: "ns1", + } + o.OrderedCollectionNSEvent(database.CollectionPins, core.ChangeEventTypeCreated, "ns2", 1) +} + +func TestUUIDCollectionWrongNS(t *testing.T) { + o := &orchestrator{ + ctx: context.Background(), + namespace: "ns1", + } + o.UUIDCollectionNSEvent(database.CollectionSubscriptions, core.ChangeEventTypeCreated, "ns2", fftypes.NewUUID()) +} diff --git a/internal/tokens/fftokens/fftokens_test.go b/internal/tokens/fftokens/fftokens_test.go index 38689c13c8..71f4756c67 100644 --- a/internal/tokens/fftokens/fftokens_test.go +++ b/internal/tokens/fftokens/fftokens_test.go @@ -766,7 +766,7 @@ func TestTransferTokensError(t *testing.T) { assert.Regexp(t, "FF10274", err) } -func TestEvents(t *testing.T) { +func TestIgnoredEvents(t *testing.T) { h, toServer, fromServer, _, done := newTestFFTokens(t) defer done() @@ -779,26 +779,32 @@ func TestEvents(t *testing.T) { msg := <-toServer assert.Equal(t, `{"data":{"id":"1"},"event":"ack"}`, string(msg)) - mcb := &tokenmocks.Callbacks{} - h.RegisterListener(mcb) - opID := fftypes.NewUUID() - txID := fftypes.NewUUID() - fromServer <- fftypes.JSONObject{ "id": "2", "event": "receipt", "data": fftypes.JSONObject{}, }.String() +} + +func TestReceiptEvents(t *testing.T) { + h, _, fromServer, _, done := newTestFFTokens(t) + defer done() + err := h.Start() + assert.NoError(t, err) + + mcb := &tokenmocks.Callbacks{} + h.RegisterListener(mcb) + opID := fftypes.NewUUID() + + // receipt: bad ID - passed through + mcb.On("TokenOpUpdate", h, "wrong", core.OpStatusFailed, "", "", mock.Anything).Return(nil).Once() fromServer <- fftypes.JSONObject{ "id": "3", "event": "receipt", "data": fftypes.JSONObject{"id": "wrong"}, // passed through to TokenOpUpdate to ignore }.String() - // receipt: bad ID - passed through - mcb.On("TokenOpUpdate", h, "wrong", core.OpStatusFailed, "", "", mock.Anything).Return(nil).Once() - // receipt: success mcb.On("TokenOpUpdate", h, "ns1:"+opID.String(), core.OpStatusSucceeded, "0xffffeeee", "", mock.Anything).Return(nil).Once() fromServer <- fftypes.JSONObject{ @@ -822,13 +828,25 @@ func TestEvents(t *testing.T) { "transactionHash": "0xffffeeee", }, }.String() +} + +func TestPoolEvents(t *testing.T) { + h, toServer, fromServer, _, done := newTestFFTokens(t) + defer done() + + err := h.Start() + assert.NoError(t, err) + + mcb := &tokenmocks.Callbacks{} + h.RegisterListener(mcb) + txID := fftypes.NewUUID() // token-pool: missing data fromServer <- fftypes.JSONObject{ "id": "6", "event": "token-pool", }.String() - msg = <-toServer + msg := <-toServer assert.Equal(t, `{"data":{"id":"6"},"event":"ack"}`, string(msg)) // token-pool: invalid uuid (success) @@ -879,12 +897,46 @@ func TestEvents(t *testing.T) { msg = <-toServer assert.Equal(t, `{"data":{"id":"8"},"event":"ack"}`, string(msg)) + // token-pool: callback fail + mcb.On("TokenPoolCreated", h, mock.MatchedBy(func(p *tokens.TokenPool) bool { + return p.PoolLocator == "F1" && p.Type == core.TokenTypeFungible && txID.Equals(p.TX.ID) && p.Event.ProtocolID == "000000000010/000020/000030" + })).Return(fmt.Errorf("pop")).Once() + fromServer <- fftypes.JSONObject{ + "id": "9", + "event": "token-pool", + "data": fftypes.JSONObject{ + "id": "000000000010/000020/000030/000040", + "type": "fungible", + "poolLocator": "F1", + "signer": "0x0", + "data": fftypes.JSONObject{"tx": txID.String()}.String(), + "blockchain": fftypes.JSONObject{ + "id": "000000000010/000020/000030", + "info": fftypes.JSONObject{ + "transactionHash": "0xffffeeee", + }, + }, + }, + }.String() +} + +func TestTransferEvents(t *testing.T) { + h, toServer, fromServer, _, done := newTestFFTokens(t) + defer done() + + err := h.Start() + assert.NoError(t, err) + + mcb := &tokenmocks.Callbacks{} + h.RegisterListener(mcb) + txID := fftypes.NewUUID() + // token-mint: missing data fromServer <- fftypes.JSONObject{ "id": "9", "event": "token-mint", }.String() - msg = <-toServer + msg := <-toServer assert.Equal(t, `{"data":{"id":"9"},"event":"ack"}`, string(msg)) // token-mint: invalid amount @@ -1061,6 +1113,42 @@ func TestEvents(t *testing.T) { msg = <-toServer assert.Equal(t, `{"data":{"id":"16"},"event":"ack"}`, string(msg)) + // token-transfer: callback fail + mcb.On("TokensTransferred", h, mock.MatchedBy(func(t *tokens.TokenTransfer) bool { + return t.Amount.Int().Int64() == 2 && t.From == "0x0" && t.To == "0x1" && t.TokenIndex == "" && messageID.Equals(t.Message) && t.PoolLocator == "F1" && t.Event.ProtocolID == "000000000010/000020/000030" + })).Return(fmt.Errorf("pop")).Once() + fromServer <- fftypes.JSONObject{ + "id": "17", + "event": "token-transfer", + "data": fftypes.JSONObject{ + "id": "000000000010/000020/000030/000040", + "poolLocator": "F1", + "signer": "0x0", + "from": "0x0", + "to": "0x1", + "amount": "2", + "data": fftypes.JSONObject{"tx": txID.String(), "message": messageID.String()}.String(), + "blockchain": fftypes.JSONObject{ + "id": "000000000010/000020/000030", + "info": fftypes.JSONObject{ + "transactionHash": "0xffffeeee", + }, + }, + }, + }.String() +} + +func TestApprovalEvents(t *testing.T) { + h, toServer, fromServer, _, done := newTestFFTokens(t) + defer done() + + err := h.Start() + assert.NoError(t, err) + + mcb := &tokenmocks.Callbacks{} + h.RegisterListener(mcb) + txID := fftypes.NewUUID() + // token-approval: success mcb.On("TokensApproved", h, mock.MatchedBy(func(t *tokens.TokenApproval) bool { return t.Approved == true && t.Operator == "0x0" && t.PoolLocator == "F1" && t.Event.ProtocolID == "000000000010/000020/000030" @@ -1084,7 +1172,7 @@ func TestEvents(t *testing.T) { }, }, }.String() - msg = <-toServer + msg := <-toServer assert.Equal(t, `{"data":{"id":"17"},"event":"ack"}`, string(msg)) // token-approval: success (no data) @@ -1108,13 +1196,35 @@ func TestEvents(t *testing.T) { // token-approval: missing data fromServer <- fftypes.JSONObject{ - "id": "9", + "id": "19", "event": "token-approval", }.String() msg = <-toServer - assert.Equal(t, `{"data":{"id":"9"},"event":"ack"}`, string(msg)) + assert.Equal(t, `{"data":{"id":"19"},"event":"ack"}`, string(msg)) - mcb.AssertExpectations(t) + // token-approval: callback fail + mcb.On("TokensApproved", h, mock.MatchedBy(func(t *tokens.TokenApproval) bool { + return t.Approved == true && t.Operator == "0x0" && t.PoolLocator == "F1" && t.Event.ProtocolID == "000000000010/000020/000030" + })).Return(fmt.Errorf("pop")).Once() + fromServer <- fftypes.JSONObject{ + "id": "20", + "event": "token-approval", + "data": fftypes.JSONObject{ + "id": "000000000010/000020/000030/000040", + "subject": "a:b", + "poolLocator": "F1", + "signer": "0x0", + "operator": "0x0", + "approved": true, + "data": fftypes.JSONObject{"tx": txID.String()}.String(), + "blockchain": fftypes.JSONObject{ + "id": "000000000010/000020/000030", + "info": fftypes.JSONObject{ + "transactionHash": "0xffffeeee", + }, + }, + }, + }.String() } func TestEventLoopReceiveClosed(t *testing.T) { From 7aed6c74ad99dfd1cd8ee9787b37f4020a7d2377 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Thu, 9 Jun 2022 15:31:47 -0400 Subject: [PATCH 28/33] Remove unneeded "name" field Signed-off-by: Andrew Richardson --- internal/namespace/manager.go | 39 ++++++++++------------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/internal/namespace/manager.go b/internal/namespace/manager.go index 2248150590..cd1a6db3df 100644 --- a/internal/namespace/manager.go +++ b/internal/namespace/manager.go @@ -98,37 +98,31 @@ type namespaceManager struct { } type blockchainPlugin struct { - name string config config.Section plugin blockchain.Plugin } type databasePlugin struct { - name string config config.Section plugin database.Plugin } type dataExchangePlugin struct { - name string config config.Section plugin dataexchange.Plugin } type sharedStoragePlugin struct { - name string config config.Section plugin sharedstorage.Plugin } type tokensPlugin struct { - name string config config.Section plugin tokens.Plugin } type identityPlugin struct { - name string config config.Section plugin identity.Plugin } @@ -300,7 +294,6 @@ func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[s } plugins[name] = tokensPlugin{ - name: name, config: config.SubSection(pluginType), plugin: plugin, } @@ -330,7 +323,6 @@ func (nm *namespaceManager) getTokensPlugins(ctx context.Context) (plugins map[s } plugins[name] = tokensPlugin{ - name: name, config: deprecatedConfig, plugin: plugin, } @@ -356,7 +348,6 @@ func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map } plugins[name] = databasePlugin{ - name: name, config: config.SubSection(pluginType), plugin: plugin, } @@ -371,7 +362,6 @@ func (nm *namespaceManager) getDatabasePlugins(ctx context.Context) (plugins map } name := "database_0" plugins[name] = databasePlugin{ - name: name, config: deprecatedDatabaseConfig.SubSection(pluginType), plugin: plugin, } @@ -416,7 +406,6 @@ func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins } plugins[name] = dataExchangePlugin{ - name: name, config: config.SubSection(pluginType), plugin: plugin, } @@ -432,7 +421,6 @@ func (nm *namespaceManager) getDataExchangePlugins(ctx context.Context) (plugins name := "dataexchange_0" plugins[name] = dataExchangePlugin{ - name: name, config: deprecatedDataexchangeConfig.SubSection(pluginType), plugin: plugin, } @@ -457,7 +445,6 @@ func (nm *namespaceManager) getIdentityPlugins(ctx context.Context) (plugins map } plugins[name] = identityPlugin{ - name: name, config: config.SubSection(pluginType), plugin: plugin, } @@ -482,7 +469,6 @@ func (nm *namespaceManager) getBlockchainPlugins(ctx context.Context) (plugins m } plugins[name] = blockchainPlugin{ - name: name, config: config.SubSection(pluginType), plugin: plugin, } @@ -498,7 +484,6 @@ func (nm *namespaceManager) getBlockchainPlugins(ctx context.Context) (plugins m name := "blockchain_0" plugins[name] = blockchainPlugin{ - name: name, config: deprecatedBlockchainConfig.SubSection(pluginType), plugin: plugin, } @@ -523,7 +508,6 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin } plugins[name] = sharedStoragePlugin{ - name: name, config: config.SubSection(pluginType), plugin: plugin, } @@ -539,7 +523,6 @@ func (nm *namespaceManager) getSharedStoragePlugins(ctx context.Context) (plugin name := "sharedstorage_0" plugins[name] = sharedStoragePlugin{ - name: name, config: deprecatedSharedStorageConfig.SubSection(pluginType), plugin: plugin, } @@ -570,8 +553,8 @@ func (nm *namespaceManager) initPlugins(ctx context.Context) (err error) { return err } } - for _, entry := range nm.plugins.tokens { - if err = entry.plugin.Init(ctx, entry.name, entry.config); err != nil { + for name, entry := range nm.plugins.tokens { + if err = entry.plugin.Init(ctx, name, entry.config); err != nil { return err } } @@ -693,7 +676,7 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") } result.Blockchain = orchestrator.BlockchainPlugin{ - Name: instance.name, + Name: pluginName, Plugin: instance.plugin, } continue @@ -703,7 +686,7 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "dataexchange") } result.DataExchange = orchestrator.DataExchangePlugin{ - Name: instance.name, + Name: pluginName, Plugin: instance.plugin, } continue @@ -713,7 +696,7 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "sharedstorage") } result.SharedStorage = orchestrator.SharedStoragePlugin{ - Name: instance.name, + Name: pluginName, Plugin: instance.plugin, } continue @@ -723,21 +706,21 @@ func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name s return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") } result.Database = orchestrator.DatabasePlugin{ - Name: instance.name, + Name: pluginName, Plugin: instance.plugin, } continue } if instance, ok := nm.plugins.tokens[pluginName]; ok { result.Tokens = append(result.Tokens, orchestrator.TokensPlugin{ - Name: instance.name, + Name: pluginName, Plugin: instance.plugin, }) continue } if instance, ok := nm.plugins.identity[pluginName]; ok { result.Identity = orchestrator.IdentityPlugin{ - Name: instance.name, + Name: pluginName, Plugin: instance.plugin, } continue @@ -764,7 +747,7 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name stri return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain") } result.Blockchain = orchestrator.BlockchainPlugin{ - Name: instance.name, + Name: pluginName, Plugin: instance.plugin, } continue @@ -780,14 +763,14 @@ func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name stri return nil, i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database") } result.Database = orchestrator.DatabasePlugin{ - Name: instance.name, + Name: pluginName, Plugin: instance.plugin, } continue } if instance, ok := nm.plugins.tokens[pluginName]; ok { result.Tokens = append(result.Tokens, orchestrator.TokensPlugin{ - Name: instance.name, + Name: pluginName, Plugin: instance.plugin, }) continue From 82467b460bb84d616166ff5b896dd878407efd70 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Mon, 13 Jun 2022 11:58:50 -0400 Subject: [PATCH 29/33] Always include namespace when querying pins Signed-off-by: Andrew Richardson --- .../postgres/000092_add_pin_namespace.down.sql | 3 +++ db/migrations/postgres/000092_add_pin_namespace.up.sql | 3 +++ db/migrations/sqlite/000092_add_pin_namespace.down.sql | 3 +++ db/migrations/sqlite/000092_add_pin_namespace.up.sql | 3 +++ docs/swagger/swagger.yaml | 10 ++++++++++ internal/events/aggregator.go | 10 +++++++--- internal/events/aggregator_batch_state.go | 4 ++++ internal/events/aggregator_test.go | 2 +- internal/events/event_manager.go | 2 +- pkg/database/plugin.go | 1 + 10 files changed, 36 insertions(+), 5 deletions(-) diff --git a/db/migrations/postgres/000092_add_pin_namespace.down.sql b/db/migrations/postgres/000092_add_pin_namespace.down.sql index 44c4c79c83..67c6e12968 100644 --- a/db/migrations/postgres/000092_add_pin_namespace.down.sql +++ b/db/migrations/postgres/000092_add_pin_namespace.down.sql @@ -1,3 +1,6 @@ BEGIN; +DROP INDEX pins_pin; +CREATE UNIQUE INDEX pins_pin ON pins(hash, batch_id, idx); + ALTER TABLE pins DROP COLUMN namespace; COMMIT; diff --git a/db/migrations/postgres/000092_add_pin_namespace.up.sql b/db/migrations/postgres/000092_add_pin_namespace.up.sql index 36d55b6340..903d70daca 100644 --- a/db/migrations/postgres/000092_add_pin_namespace.up.sql +++ b/db/migrations/postgres/000092_add_pin_namespace.up.sql @@ -2,4 +2,7 @@ BEGIN; ALTER TABLE pins ADD COLUMN namespace VARCHAR(64); UPDATE pins SET namespace = 'ff_system'; ALTER TABLE pins ALTER COLUMN namespace SET NOT NULL; + +DROP INDEX pins_pin; +CREATE UNIQUE INDEX pins_pin ON pins(namespace, hash, batch_id, idx); COMMIT; diff --git a/db/migrations/sqlite/000092_add_pin_namespace.down.sql b/db/migrations/sqlite/000092_add_pin_namespace.down.sql index 3871b630f0..0f819fec77 100644 --- a/db/migrations/sqlite/000092_add_pin_namespace.down.sql +++ b/db/migrations/sqlite/000092_add_pin_namespace.down.sql @@ -1 +1,4 @@ +DROP INDEX pins_pin; +CREATE UNIQUE INDEX pins_pin ON pins(hash, batch_id, idx); + ALTER TABLE pins DROP COLUMN namespace; diff --git a/db/migrations/sqlite/000092_add_pin_namespace.up.sql b/db/migrations/sqlite/000092_add_pin_namespace.up.sql index df14865e9f..0c4e0b75c6 100644 --- a/db/migrations/sqlite/000092_add_pin_namespace.up.sql +++ b/db/migrations/sqlite/000092_add_pin_namespace.up.sql @@ -1,2 +1,5 @@ ALTER TABLE pins ADD COLUMN namespace VARCHAR(64); UPDATE pins SET namespace = "ff_system"; + +DROP INDEX pins_pin; +CREATE UNIQUE INDEX pins_pin ON pins(namespace, hash, batch_id, idx); diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index e41b67d8b4..b80be7cd20 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -19901,6 +19901,11 @@ paths: name: masked 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: sequence @@ -27395,6 +27400,11 @@ paths: name: masked 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: sequence diff --git a/internal/events/aggregator.go b/internal/events/aggregator.go index ac1d7c1697..99c374bb42 100644 --- a/internal/events/aggregator.go +++ b/internal/events/aggregator.go @@ -45,6 +45,7 @@ const ( type aggregator struct { ctx context.Context + namespace string database database.Plugin messaging privatemessaging.Manager definitions definitions.DefinitionHandler @@ -64,10 +65,11 @@ type batchCacheEntry struct { manifest *core.BatchManifest } -func newAggregator(ctx context.Context, di database.Plugin, bi blockchain.Plugin, pm privatemessaging.Manager, sh definitions.DefinitionHandler, im identity.Manager, dm data.Manager, en *eventNotifier, mm metrics.Manager) *aggregator { +func newAggregator(ctx context.Context, ns string, di database.Plugin, bi blockchain.Plugin, pm privatemessaging.Manager, sh definitions.DefinitionHandler, im identity.Manager, dm data.Manager, en *eventNotifier, mm metrics.Manager) *aggregator { batchSize := config.GetInt(coreconfig.EventAggregatorBatchSize) ag := &aggregator{ ctx: log.WithLogField(ctx, "role", "aggregator"), + namespace: ns, database: di, messaging: pm, definitions: sh, @@ -94,7 +96,7 @@ func newAggregator(ctx context.Context, di database.Plugin, bi blockchain.Plugin Factor: config.GetFloat64(coreconfig.EventAggregatorRetryFactor), }, firstEvent: &firstEvent, - namespace: "pins", // not a real namespace (used only for logging) + namespace: ns, offsetType: core.OffsetTypeAggregator, offsetName: aggregatorOffsetName, newEventsHandler: ag.processPinsEventsHandler, @@ -160,6 +162,7 @@ func (ag *aggregator) rewindOffchainBatches() (bool, int64) { _ = ag.retry.Do(ag.ctx, "check for off-chain batch deliveries", func(attempt int) (retry bool, err error) { pfb := database.PinQueryFactory.NewFilter(ag.ctx) pinFilter := pfb.And( + pfb.Eq("namespace", ag.namespace), pfb.In("batch", batchIDs), pfb.Eq("dispatched", false), ).Sort("sequence").Limit(1) // only need the one oldest sequence @@ -223,7 +226,8 @@ func (ag *aggregator) processPinsEventsHandler(items []core.LocallySequenced) (r func (ag *aggregator) getPins(ctx context.Context, filter database.Filter, offset int64) ([]core.LocallySequenced, error) { log.L(ctx).Tracef("Reading page of pins > %d (first pin would be %d)", offset, offset+1) - pins, _, err := ag.database.GetPins(ctx, filter) + fb := database.PinQueryFactory.NewFilter(ctx) + pins, _, err := ag.database.GetPins(ctx, fb.And(filter, fb.Eq("namespace", ag.namespace))) ls := make([]core.LocallySequenced, len(pins)) for i, p := range pins { ls[i] = p diff --git a/internal/events/aggregator_batch_state.go b/internal/events/aggregator_batch_state.go index ffad4d46ce..2613cbd787 100644 --- a/internal/events/aggregator_batch_state.go +++ b/internal/events/aggregator_batch_state.go @@ -33,6 +33,7 @@ import ( func newBatchState(ag *aggregator) *batchState { return &batchState{ + namespace: ag.namespace, database: ag.database, messaging: ag.messaging, data: ag.data, @@ -95,6 +96,7 @@ type dispatchedMessage struct { // Runs in a database operation group/tranaction, which will be the same as phase (1) if there // are no pre-finalize handlers registered. type batchState struct { + namespace string database database.Plugin messaging privatemessaging.Manager data data.Manager @@ -171,6 +173,7 @@ func (bs *batchState) CheckUnmaskedContextReady(ctx context.Context, contextUnma // We need to check there's no earlier sequences with the same unmasked context fb := database.PinQueryFactory.NewFilterLimit(ctx, 1) // only need the first one filter := fb.And( + fb.Eq("namespace", bs.namespace), fb.Eq("hash", contextUnmasked), fb.Eq("dispatched", false), fb.Lt("sequence", firstMsgPinSequence), @@ -445,6 +448,7 @@ func (bs *batchState) attemptContextInit(ctx context.Context, msg *core.Message, // Check none of the other zerohashes exist before us in the stream fb := database.PinQueryFactory.NewFilter(ctx) filter := fb.And( + fb.Eq("namespace", bs.namespace), fb.In("hash", zeroHashes), fb.Eq("dispatched", false), fb.Lt("sequence", pinnedSequence), diff --git a/internal/events/aggregator_test.go b/internal/events/aggregator_test.go index e52cb2ab9f..9e4e6007b4 100644 --- a/internal/events/aggregator_test.go +++ b/internal/events/aggregator_test.go @@ -59,7 +59,7 @@ func newTestAggregatorCommon(metrics bool) (*aggregator, func()) { mmi.On("IsMetricsEnabled").Return(metrics) mbi.On("VerifierType").Return(core.VerifierTypeEthAddress) ctx, cancel := context.WithCancel(context.Background()) - ag := newAggregator(ctx, mdi, mbi, mpm, msh, mim, mdm, newEventNotifier(ctx, "ut"), mmi) + ag := newAggregator(ctx, "ns1", mdi, mbi, mpm, msh, mim, mdm, newEventNotifier(ctx, "ut"), mmi) return ag, func() { cancel() ag.batchCache.Stop() diff --git a/internal/events/event_manager.go b/internal/events/event_manager.go index 293d32c553..33c76440ed 100644 --- a/internal/events/event_manager.go +++ b/internal/events/event_manager.go @@ -140,7 +140,7 @@ func NewEventManager(ctx context.Context, ns string, ni sysmessaging.LocalNodeIn defaultTransport: config.GetString(coreconfig.EventTransportsDefault), newEventNotifier: newEventNotifier, newPinNotifier: newPinNotifier, - aggregator: newAggregator(ctx, di, bi, pm, dh, im, dm, newPinNotifier, mm), + aggregator: newAggregator(ctx, ns, di, bi, pm, dh, im, dm, newPinNotifier, mm), metrics: mm, chainListenerCache: ccache.New(ccache.Configure().MaxSize(config.GetByteSize(coreconfig.EventListenerTopicCacheSize))), chainListenerCacheTTL: config.GetDuration(coreconfig.EventListenerTopicCacheTTL), diff --git a/pkg/database/plugin.go b/pkg/database/plugin.go index b1ead72b20..07cb114965 100644 --- a/pkg/database/plugin.go +++ b/pkg/database/plugin.go @@ -822,6 +822,7 @@ var EventQueryFactory = &queryFields{ // PinQueryFactory filter fields for parked contexts var PinQueryFactory = &queryFields{ + "namespace": &StringField{}, "sequence": &Int64Field{}, "masked": &BoolField{}, "hash": &Bytes32Field{}, From dd4adf93cc28a513544a4132057b1829ad934e2f Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Mon, 13 Jun 2022 14:57:04 -0400 Subject: [PATCH 30/33] Fix for pin filter Signed-off-by: Andrew Richardson --- internal/events/aggregator.go | 6 +++--- internal/events/aggregator_batch_state.go | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/events/aggregator.go b/internal/events/aggregator.go index 99c374bb42..3b0e3c299d 100644 --- a/internal/events/aggregator.go +++ b/internal/events/aggregator.go @@ -103,7 +103,8 @@ func newAggregator(ctx context.Context, ns string, di database.Plugin, bi blockc getItems: ag.getPins, queryFactory: database.PinQueryFactory, addCriteria: func(af database.AndFilter) database.AndFilter { - return af.Condition(af.Builder().Eq("dispatched", false)) + fb := af.Builder() + return af.Condition(fb.Eq("dispatched", false), fb.Eq("namespace", ns)) }, maybeRewind: ag.rewindOffchainBatches, }) @@ -226,8 +227,7 @@ func (ag *aggregator) processPinsEventsHandler(items []core.LocallySequenced) (r func (ag *aggregator) getPins(ctx context.Context, filter database.Filter, offset int64) ([]core.LocallySequenced, error) { log.L(ctx).Tracef("Reading page of pins > %d (first pin would be %d)", offset, offset+1) - fb := database.PinQueryFactory.NewFilter(ctx) - pins, _, err := ag.database.GetPins(ctx, fb.And(filter, fb.Eq("namespace", ag.namespace))) + pins, _, err := ag.database.GetPins(ctx, filter) ls := make([]core.LocallySequenced, len(pins)) for i, p := range pins { ls[i] = p diff --git a/internal/events/aggregator_batch_state.go b/internal/events/aggregator_batch_state.go index 2613cbd787..8a7a63ba6a 100644 --- a/internal/events/aggregator_batch_state.go +++ b/internal/events/aggregator_batch_state.go @@ -309,6 +309,7 @@ func (bs *batchState) flushPins(ctx context.Context) error { filter := fb.Or() for batchID, indexes := range pinsDispatched { filter.Condition(fb.And( + fb.Eq("namespace", bs.namespace), fb.Eq("batch", batchID), fb.In("index", indexes), )) From f7559c9dfefdf58cdf18ee28934a628d4520c9d0 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Mon, 13 Jun 2022 15:03:17 -0400 Subject: [PATCH 31/33] Return empty list for identity plugins Signed-off-by: Andrew Richardson --- internal/orchestrator/status.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/orchestrator/status.go b/internal/orchestrator/status.go index 398ab15048..d33e73b495 100644 --- a/internal/orchestrator/status.go +++ b/internal/orchestrator/status.go @@ -69,6 +69,7 @@ func (or *orchestrator) getPlugins() core.NodeStatusPlugins { DataExchange: dataexchangeArray, Events: or.events.GetPlugins(), Tokens: tokensArray, + Identity: []*core.NodeStatusPlugin{}, } } From 140567d66429b49114c0219343fb40023eced401 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Tue, 14 Jun 2022 13:00:44 -0400 Subject: [PATCH 32/33] Use "different namespace" instead of "wrong namespace" in log Signed-off-by: Andrew Richardson --- internal/events/batch_pin_complete.go | 2 +- internal/events/blockchain_event.go | 2 +- internal/events/dx_callbacks.go | 4 ++-- internal/events/token_pool_created.go | 4 ++-- internal/events/tokens_approved.go | 2 +- internal/events/tokens_transferred.go | 2 +- internal/operations/operation_updater.go | 2 +- internal/orchestrator/persistence_events.go | 6 +++--- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/internal/events/batch_pin_complete.go b/internal/events/batch_pin_complete.go index 2903219a2c..bfb391b258 100644 --- a/internal/events/batch_pin_complete.go +++ b/internal/events/batch_pin_complete.go @@ -41,7 +41,7 @@ func (em *eventManager) BatchPinComplete(bi blockchain.Plugin, batchPin *blockch return nil // move on } if batchPin.Namespace != em.namespace { - log.L(em.ctx).Debugf("Ignoring BatchPin from wrong namespace '%s'", batchPin.Namespace) + log.L(em.ctx).Debugf("Ignoring BatchPin from different namespace '%s'", batchPin.Namespace) return nil // move on } diff --git a/internal/events/blockchain_event.go b/internal/events/blockchain_event.go index 4cee6ae4f6..a944fa8072 100644 --- a/internal/events/blockchain_event.go +++ b/internal/events/blockchain_event.go @@ -128,7 +128,7 @@ func (em *eventManager) BlockchainEvent(event *blockchain.EventWithSubscription) return nil // no retry } if sub.Namespace != em.namespace { - log.L(em.ctx).Debugf("Ignoring blockchain event from wrong namespace '%s'", sub.Namespace) + log.L(em.ctx).Debugf("Ignoring blockchain event from different namespace '%s'", sub.Namespace) return nil } diff --git a/internal/events/dx_callbacks.go b/internal/events/dx_callbacks.go index a873fa9472..75895c875f 100644 --- a/internal/events/dx_callbacks.go +++ b/internal/events/dx_callbacks.go @@ -199,7 +199,7 @@ func (em *eventManager) messageReceived(dx dataexchange.Plugin, event dataexchan return } if wrapper.Batch.Namespace != em.namespace { - log.L(em.ctx).Debugf("Ignoring batch from wrong namespace '%s'", wrapper.Batch.Namespace) + log.L(em.ctx).Debugf("Ignoring batch from different namespace '%s'", wrapper.Batch.Namespace) return } l.Infof("Private batch received from %s peer '%s' (len=%d)", dx.Name(), mr.PeerID, len(mr.Data)) @@ -223,7 +223,7 @@ func (em *eventManager) privateBlobReceived(dx dataexchange.Plugin, event dataex return } if br.Namespace != em.namespace { - log.L(em.ctx).Debugf("Ignoring blob from wrong namespace '%s'", br.Namespace) + log.L(em.ctx).Debugf("Ignoring blob from different namespace '%s'", br.Namespace) return } diff --git a/internal/events/token_pool_created.go b/internal/events/token_pool_created.go index a8c3346018..f96e17d9af 100644 --- a/internal/events/token_pool_created.go +++ b/internal/events/token_pool_created.go @@ -148,7 +148,7 @@ func (em *eventManager) TokenPoolCreated(ti tokens.Plugin, pool *tokens.TokenPoo } if existingPool != nil { if existingPool.Namespace != em.namespace { - log.L(em.ctx).Debugf("Ignoring token pool from wrong namespace '%s'", existingPool.Namespace) + log.L(em.ctx).Debugf("Ignoring token pool from different namespace '%s'", existingPool.Namespace) return nil } if existingPool.State == core.TokenPoolStateConfirmed { @@ -168,7 +168,7 @@ func (em *eventManager) TokenPoolCreated(ti tokens.Plugin, pool *tokens.TokenPoo return err } else if announcePool != nil { if announcePool.Namespace != em.namespace { - log.L(em.ctx).Debugf("Ignoring token pool from wrong namespace '%s'", announcePool.Namespace) + log.L(em.ctx).Debugf("Ignoring token pool from different namespace '%s'", announcePool.Namespace) announcePool = nil return nil } diff --git a/internal/events/tokens_approved.go b/internal/events/tokens_approved.go index 9e07ee89d0..bbb0796662 100644 --- a/internal/events/tokens_approved.go +++ b/internal/events/tokens_approved.go @@ -79,7 +79,7 @@ func (em *eventManager) persistTokenApproval(ctx context.Context, approval *toke return false, nil } if pool.Namespace != em.namespace { - log.L(em.ctx).Debugf("Ignoring token approval from wrong namespace '%s'", pool.Namespace) + log.L(em.ctx).Debugf("Ignoring token approval from different namespace '%s'", pool.Namespace) return false, nil } approval.Namespace = pool.Namespace diff --git a/internal/events/tokens_transferred.go b/internal/events/tokens_transferred.go index e819924b00..012ec33a15 100644 --- a/internal/events/tokens_transferred.go +++ b/internal/events/tokens_transferred.go @@ -79,7 +79,7 @@ func (em *eventManager) persistTokenTransfer(ctx context.Context, transfer *toke return false, nil } if pool.Namespace != em.namespace { - log.L(em.ctx).Debugf("Ignoring token transfer from wrong namespace '%s'", pool.Namespace) + log.L(em.ctx).Debugf("Ignoring token transfer from different namespace '%s'", pool.Namespace) return false, nil } transfer.Namespace = pool.Namespace diff --git a/internal/operations/operation_updater.go b/internal/operations/operation_updater.go index 4fea4cca29..3906e66245 100644 --- a/internal/operations/operation_updater.go +++ b/internal/operations/operation_updater.go @@ -113,7 +113,7 @@ func (ou *operationUpdater) SubmitOperationUpdate(ctx context.Context, update *O return } if ns != ou.manager.namespace { - log.L(ou.ctx).Debugf("Ignoring operation update from wrong namespace '%s'", ns) + log.L(ou.ctx).Debugf("Ignoring operation update from different namespace '%s'", ns) return } diff --git a/internal/orchestrator/persistence_events.go b/internal/orchestrator/persistence_events.go index 1374682921..1b5ac3d53d 100644 --- a/internal/orchestrator/persistence_events.go +++ b/internal/orchestrator/persistence_events.go @@ -25,7 +25,7 @@ import ( func (or *orchestrator) OrderedUUIDCollectionNSEvent(resType database.OrderedUUIDCollectionNS, eventType core.ChangeEventType, ns string, id *fftypes.UUID, sequence int64) { if ns != or.namespace { - log.L(or.ctx).Debugf("Ignoring database event from wrong namespace '%s'", ns) + log.L(or.ctx).Debugf("Ignoring database event from different namespace '%s'", ns) return } switch { @@ -38,7 +38,7 @@ func (or *orchestrator) OrderedUUIDCollectionNSEvent(resType database.OrderedUUI func (or *orchestrator) OrderedCollectionNSEvent(resType database.OrderedCollectionNS, eventType core.ChangeEventType, ns string, sequence int64) { if ns != or.namespace { - log.L(or.ctx).Debugf("Ignoring database event from wrong namespace '%s'", ns) + log.L(or.ctx).Debugf("Ignoring database event from different namespace '%s'", ns) return } if eventType == core.ChangeEventTypeCreated && resType == database.CollectionPins { @@ -48,7 +48,7 @@ func (or *orchestrator) OrderedCollectionNSEvent(resType database.OrderedCollect func (or *orchestrator) UUIDCollectionNSEvent(resType database.UUIDCollectionNS, eventType core.ChangeEventType, ns string, id *fftypes.UUID) { if ns != or.namespace { - log.L(or.ctx).Debugf("Ignoring database event from wrong namespace '%s'", ns) + log.L(or.ctx).Debugf("Ignoring database event from different namespace '%s'", ns) return } switch { From f96daefe64e73b6abf6fafd5390d87a5d52592d2 Mon Sep 17 00:00:00 2001 From: Andrew Richardson Date: Tue, 14 Jun 2022 13:08:11 -0400 Subject: [PATCH 33/33] Replace "/spi/v1/operations" with "/spi/v1/namespaces/{ns}/operations" Signed-off-by: Andrew Richardson --- internal/apiserver/route_spi_get_ops.go | 6 +++--- internal/apiserver/route_spi_get_ops_test.go | 12 +++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/internal/apiserver/route_spi_get_ops.go b/internal/apiserver/route_spi_get_ops.go index 5b0d4b9b0e..b96f3b29ac 100644 --- a/internal/apiserver/route_spi_get_ops.go +++ b/internal/apiserver/route_spi_get_ops.go @@ -27,7 +27,7 @@ import ( var spiGetOps = &ffapi.Route{ Name: "spiGetOps", - Path: "operations", + Path: "namespaces/{ns}/operations", Method: http.MethodGet, QueryParams: nil, Description: coremsgs.APIEndpointsAdminGetOps, @@ -37,8 +37,8 @@ var spiGetOps = &ffapi.Route{ Extensions: &coreExtensions{ FilterFactory: database.OperationQueryFactory, CoreJSONHandler: func(r *ffapi.APIRequest, cr *coreRequest) (output interface{}, err error) { - // TODO: cr.or will be nil (this must be converted to a namespaced query) - return filterResult(cr.or.GetOperations(cr.ctx, cr.filter)) + or := cr.mgr.Orchestrator(r.PP["ns"]) + return filterResult(or.GetOperations(cr.ctx, cr.filter)) }, }, } diff --git a/internal/apiserver/route_spi_get_ops_test.go b/internal/apiserver/route_spi_get_ops_test.go index 7d6f5b26ad..49ef905495 100644 --- a/internal/apiserver/route_spi_get_ops_test.go +++ b/internal/apiserver/route_spi_get_ops_test.go @@ -20,18 +20,20 @@ import ( "net/http/httptest" "testing" + "github.com/hyperledger/firefly/pkg/core" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) func TestSPIGetOperations(t *testing.T) { - _, r := newTestSPIServer() - req := httptest.NewRequest("GET", "/spi/v1/operations", nil) + or, r := newTestSPIServer() + req := httptest.NewRequest("GET", "/spi/v1/namespaces/ns1/operations", nil) req.Header.Set("Content-Type", "application/json; charset=utf-8") res := httptest.NewRecorder() - assert.Panics(t, func() { - r.ServeHTTP(res, req) - }) + or.On("GetOperations", mock.Anything, mock.Anything). + Return([]*core.Operation{}, nil, nil) + r.ServeHTTP(res, req) assert.Equal(t, 200, res.Result().StatusCode) }