├── .codecov.yml
├── .editorconfig
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── proposal.md
│ └── question.md
├── pull_request_template.md
├── scripts
│ └── get_release_version.py
└── workflows
│ └── build.yaml
├── .gitignore
├── CONTRIBUTING.md
├── Dapr.PluggableComponents.Complete.sln
├── Directory.Packages.props
├── LICENSE
├── NuGet.Config
├── README.md
├── assets
└── logo-transparent.png
├── daprdocs
└── content
│ └── en
│ └── dotnet-sdk-docs
│ ├── _index.md
│ ├── dotnet-advanced
│ ├── _index.md
│ ├── dotnet-application-environment.md
│ ├── dotnet-component-lifetime.md
│ └── dotnet-multiple-services.md
│ ├── dotnet-bindings
│ └── _index.md
│ ├── dotnet-pub-sub
│ └── _index.md
│ └── dotnet-state-store
│ └── _index.md
├── samples
├── AzureStorageQueuesPubSubSample
│ ├── AzureStorageQueuesPubSub.cs
│ ├── AzureStorageQueuesPubSubSample.csproj
│ ├── Program.cs
│ ├── README.md
│ ├── appsettings.Development.json
│ └── appsettings.json
├── Directory.Build.props
├── DiscordBindingSample
│ ├── DiscordBinding.cs
│ ├── DiscordBindingSample.csproj
│ ├── Program.cs
│ ├── README.md
│ ├── appsettings.Development.json
│ └── appsettings.json
└── MemoryStateStoreSample
│ ├── MemoryStateStoreSample.csproj
│ ├── Program.cs
│ ├── Services
│ └── MemoryStateStore.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
└── src
├── Dapr.PluggableComponents.AspNetCore
├── Dapr.PluggableComponents.AspNetCore.csproj
├── DaprPluggableComponentsApplication.cs
├── DaprPluggableComponentsRegistry.cs
├── DaprPluggableComponentsServiceBuilder.cs
├── DaprPluggableComponentsServiceOptions.cs
├── IDaprPluggableComponentsRegistrar.cs
├── MultiplexedComponentProvider.cs
├── RegisteredComponentProvider.cs
├── Resources.Designer.cs
├── Resources.resx
├── WebApplicationBuilderExtensions.cs
└── WebApplicationExtensions.cs
├── Dapr.PluggableComponents.Protos
└── Dapr.PluggableComponents.Protos.csproj
├── Dapr.PluggableComponents.Tests
├── Adaptors
│ ├── AdaptorFixture.cs
│ ├── AsyncStreamReader.cs
│ ├── InputBindingAdaptorTests.cs
│ ├── OutputBindingAdaptorTests.cs
│ ├── PubSubAdaptorTests.cs
│ ├── StateStoreAdaptorTests.cs
│ ├── TestServerCallContext.cs
│ └── TransactionalStateStoreAdaptorTests.cs
├── AssemblyInfo.cs
├── Components
│ ├── Bindings
│ │ ├── InputBindingReadRequestTests.cs
│ │ ├── InputBindingReadResponseTests.cs
│ │ ├── MockCombinedBinding.cs
│ │ ├── MockInputBinding.cs
│ │ ├── MockOutputBinding.cs
│ │ ├── OutputBindingInvokeRequestTests.cs
│ │ └── OutputBindingInvokeResponseTests.cs
│ ├── IMockPluggableComponent.cs
│ ├── PubSub
│ │ ├── MockPubSub.cs
│ │ ├── PubSubPublishRequestTests.cs
│ │ ├── PubSubPullMessagesResponseTests.cs
│ │ └── PubSubPullMessagesTopicTests.cs
│ └── StateStore
│ │ ├── MockBulkStateStore.cs
│ │ ├── MockQueryableStateStore.cs
│ │ ├── MockStateStore.cs
│ │ ├── MockTransactionalStateStore.cs
│ │ ├── StateStoreBulkStateItemTests.cs
│ │ ├── StateStoreDeleteRequestTests.cs
│ │ ├── StateStoreGetRequestTests.cs
│ │ ├── StateStoreGetResponseTests.cs
│ │ ├── StateStoreQueryItemTests.cs
│ │ ├── StateStoreQueryPaginationTests.cs
│ │ ├── StateStoreQueryRequestTests.cs
│ │ ├── StateStoreQueryResponseTests.cs
│ │ ├── StateStoreQuerySortingTests.cs
│ │ ├── StateStoreQueryTests.cs
│ │ ├── StateStoreSetRequestTests.cs
│ │ ├── StateStoreStateOptionsTests.cs
│ │ ├── StateStoreTransactOperationTests.cs
│ │ └── StateStoreTransactRequestTests.cs
├── ConversionAssert.cs
├── Dapr.PluggableComponents.Tests.csproj
├── DaprPluggableComponentsApplicationTests.cs
├── DaprPluggableComponentsServiceBuilderTests.cs
├── SocketFixture.cs
├── TestConstants.cs
└── Unit.cs
├── Dapr.PluggableComponents.sln
├── Dapr.PluggableComponents
├── Adaptors
│ ├── IDaprPluggableComponentProvider.cs
│ ├── InputBindingAdaptor.cs
│ ├── OutputBindingAdaptor.cs
│ ├── PubSubAdaptor.cs
│ ├── QueryableStateStoreAdaptor.cs
│ ├── StateStoreAdaptor.cs
│ └── TransactionalStateStoreAdaptor.cs
├── AssemblyInfo.cs
├── Components
│ ├── Bindings
│ │ ├── IInputBinding.cs
│ │ ├── IOutputBinding.cs
│ │ ├── InputBindingReadRequest.cs
│ │ ├── InputBindingReadResponse.cs
│ │ ├── OutputBindingInvokeRequest.cs
│ │ └── OutputBindingInvokeResponse.cs
│ ├── IPluggableComponent.cs
│ ├── IPluggableComponentFeatures.cs
│ ├── IPluggableComponentLiveness.cs
│ ├── MessageDeliveryHandler.cs
│ ├── MetadataRequest.cs
│ ├── PubSub
│ │ ├── IPubSub.cs
│ │ ├── PubSubPublishRequest.cs
│ │ ├── PubSubPullMessagesResponse.cs
│ │ └── PubSubPullMessagesTopic.cs
│ └── StateStore
│ │ ├── BulkDeleteRowMismatchException.cs
│ │ ├── ETagErrors.cs
│ │ ├── ETagInvalidException.cs
│ │ ├── ETagMismatchException.cs
│ │ ├── IBulkStateStore.cs
│ │ ├── IQueryableStateStore.cs
│ │ ├── IStateStore.cs
│ │ ├── ITransactionalStateStore.cs
│ │ ├── StateStoreBulkStateItem.cs
│ │ ├── StateStoreDeleteRequest.cs
│ │ ├── StateStoreGetRequest.cs
│ │ ├── StateStoreGetResponse.cs
│ │ ├── StateStoreQuery.cs
│ │ ├── StateStoreQueryItem.cs
│ │ ├── StateStoreQueryPagination.cs
│ │ ├── StateStoreQueryRequest.cs
│ │ ├── StateStoreQueryResponse.cs
│ │ ├── StateStoreQuerySorting.cs
│ │ ├── StateStoreSetRequest.cs
│ │ ├── StateStoreStateOptions.cs
│ │ ├── StateStoreTransactOperation.cs
│ │ └── StateStoreTransactRequest.cs
├── Constants.cs
├── Dapr.PluggableComponents.csproj
├── Resources.Designer.cs
├── Resources.resx
└── Utilities
│ └── MapFieldExtensions.cs
├── Directory.Build.props
└── key.snk
/.codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | status:
3 | project:
4 | default:
5 | # basic
6 | target: auto
7 | threshold: 0%
8 |
9 | ignore:
10 | - "samples" # Samples
11 | - "src/Dapr.PluggableComponents.Tests" # Tests
12 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Report a bug in the .NET Dapr Pluggable Components SDK
4 | title: ''
5 | labels: kind/bug
6 | assignees: ''
7 |
8 | ---
9 | ## Expected Behavior
10 |
11 |
12 |
13 |
14 | ## Actual Behavior
15 |
16 |
17 |
18 |
19 | ## Steps to Reproduce the Problem
20 |
21 |
22 |
23 | ## Release Note
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | RELEASE NOTE:
32 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/proposal.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Proposal
3 | about: Create a proposal for the .NET Dapr Pluggable Components SDK
4 | title: ''
5 | labels: kind/proposal
6 | assignees: ''
7 |
8 | ---
9 | ## Describe the proposal
10 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Question
3 | about: Ask a question about the .NET Dapr Pluggable Components SDK
4 | title: ''
5 | labels: kind/question
6 | assignees: ''
7 |
8 | ---
9 | ## Ask your question here
10 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # Description
2 |
3 | _Please explain the changes you've made_
4 |
5 | ## Issue reference
6 |
7 | We strive to have all PR being opened based on an issue, where the problem or feature have been discussed prior to implementation.
8 |
9 | Please reference the issue this PR will close: #_[issue number]_
10 |
11 | ## Checklist
12 |
13 | Please make sure you've completed the relevant tasks for this PR, out of the following list:
14 |
15 | * [ ] Code compiles correctly
16 | * [ ] Created/updated tests
17 | * [ ] Extended the documentation
18 |
--------------------------------------------------------------------------------
/.github/scripts/get_release_version.py:
--------------------------------------------------------------------------------
1 | # ------------------------------------------------------------
2 | # Copyright 2023 The Dapr Authors
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | # http://www.apache.org/licenses/LICENSE-2.0
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS,
9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | # See the License for the specific language governing permissions and
11 | # limitations under the License.
12 | # ------------------------------------------------------------
13 |
14 | # This script parses release version from Git tag and set the parsed version to
15 | # environment variable, REL_VERSION.
16 |
17 | import os
18 | import sys
19 |
20 | gitRef = os.getenv("GITHUB_REF")
21 | tagRefPrefix = "refs/tags/v"
22 |
23 | with open(os.getenv("GITHUB_ENV"), "a") as githubEnv:
24 | if gitRef is None or not gitRef.startswith(tagRefPrefix):
25 | githubEnv.write("REL_VERSION=edge\n")
26 | print ("This is daily build from {}...".format(gitRef))
27 | sys.exit(0)
28 |
29 | releaseVersion = gitRef[len(tagRefPrefix):]
30 | releaseNotePath="docs/release_notes/v{}.md".format(releaseVersion)
31 |
32 | if gitRef.find("-rc.") > 0:
33 | print ("Release Candidate build from {}...".format(gitRef))
34 | else:
35 | # Set LATEST_RELEASE to true
36 | githubEnv.write("LATEST_RELEASE=true\n")
37 | print ("Release build from {}...".format(gitRef))
38 |
39 | githubEnv.write("REL_VERSION={}\n".format(releaseVersion))
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Everything in the external/packages directory as nuget packages are restored here.
3 | /nuget/restored_packages/*
4 |
5 | # Build generated files in src
6 | /src/**/objd/**/*
7 | /src/**/obj/**/*
8 | /src/**/bin/**/*
9 | /src/**/gen/**/*
10 | /src/**/StyleCop.Cache
11 |
12 | # components generated by Dapr when run in samples project directory.
13 | /samples/**/components/*.yaml
14 |
15 | # launchSettings.json for samples and tests
16 | /samples/**/Properties/launchSettings.json
17 | /test/**/Properties/launchSettings.json
18 |
19 | # Test logs
20 | TestResults/
21 |
22 | # MSBuild's log file
23 | msbuild.log
24 |
25 | # test results
26 | TestResults/
27 |
28 | # Build.exe
29 | *.err
30 | *.wrn
31 | *.log
32 | *.prf
33 | *.trc
34 | *.nupkg
35 | buildd.dbb
36 | build.dbb
37 | buildd.evt
38 | build.evt
39 |
40 | ###
41 | Repository Bloat Risks
42 | ###
43 | *.exe
44 | *.dll
45 | *.lib
46 | *.pdb
47 | *.wim
48 | *.zip
49 | *.gz
50 | *.meta
51 | *.obj
52 | *.tmp
53 | *.tmp_proj
54 | *.log
55 | .builds
56 |
57 | ## Ignore Visual Studio temporary files, build results, and
58 | ## files generated by popular Visual Studio add-ons.
59 | **/.vs/**/*
60 | /test/**/v15/Server/sqlite3/**/*
61 |
62 | # User-specific files
63 | *.suo
64 | *.user
65 | *.userosscache
66 | *.sln.docstates
67 |
68 | # Build results
69 | [Dd]ebug/
70 | [Dd]ebugPublic/
71 | [Rr]elease/
72 | [Rr]eleases/
73 | x64/
74 | x86/
75 | build/
76 | bld/
77 | [Bb]in/
78 | [Oo]bj/
79 |
80 | #drop folder
81 | /src/drop/**/*
82 |
83 | # Roslyn cache directories
84 | *.ide/
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | /drop
91 |
92 | # VS Code
93 | .vscode/
94 |
95 | # Jetbrains
96 | .idea/
97 |
98 | # coverlet code coverage results
99 | coverage.json
100 | .fake
101 | .ionide
102 |
103 | # Examples bloat
104 | examples/**/tmp
--------------------------------------------------------------------------------
/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/assets/logo-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dapr-sandbox/components-dotnet-sdk/ddba8197c78eba41ab4fb1be119867b0d334a0a1/assets/logo-transparent.png
--------------------------------------------------------------------------------
/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | type: docs
3 | title: "Advanced uses of the Dapr pluggable components .NET SDK"
4 | linkTitle: "Advanced"
5 | weight: 2000
6 | description: How to use advanced techniques with with the Dapr pluggable components .NET SDK
7 | is_preview: true
8 | ---
9 |
10 | While not typically needed by most, these guides show advanced ways to can configure your .NET pluggable components.
--------------------------------------------------------------------------------
/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-component-lifetime.md:
--------------------------------------------------------------------------------
1 | ---
2 | type: docs
3 | title: "Lifetimes of .NET Dapr pluggable components"
4 | linkTitle: "Component lifetime"
5 | weight: 1000
6 | description: How to control the lifetime of a .NET pluggable component
7 | no_list: true
8 | is_preview: true
9 | ---
10 |
11 | There are two ways to register a component:
12 |
13 | - The component operates as a singleton, with lifetime managed by the SDK
14 | - A component's lifetime is determined by the pluggable component and can be multi-instance or a singleton, as needed
15 |
16 | ## Singleton components
17 |
18 | Components registered _by type_ are singletons: one instance will serve all configured components of that type associated with that socket. This approach is best when only a single component of that type exists and is shared amongst Dapr applications.
19 |
20 | ```csharp
21 | var app = DaprPluggableComponentsApplication.Create();
22 |
23 | app.RegisterService(
24 | "service-a",
25 | serviceBuilder =>
26 | {
27 | serviceBuilder.RegisterStateStore();
28 | });
29 |
30 | app.Run();
31 |
32 | class SingletonStateStore : IStateStore
33 | {
34 | // ...
35 | }
36 | ```
37 |
38 | ## Multi-instance components
39 |
40 | Components can be registered by passing a "factory method". This method will be called for each configured component of that type associated with that socket. The method returns the instance to associate with that component (whether shared or not). This approach is best when multiple components of the same type may be configured with different sets of metadata, when component operations need to be isolated from one another, etc.
41 |
42 | The factory method will be passed context, such as the ID of the configured Dapr component, that can be used to differentiate component instances.
43 |
44 | ```csharp
45 | var app = DaprPluggableComponentsApplication.Create();
46 |
47 | app.RegisterService(
48 | "service-a",
49 | serviceBuilder =>
50 | {
51 | serviceBuilder.RegisterStateStore(
52 | context =>
53 | {
54 | return new MultiStateStore(context.InstanceId);
55 | });
56 | });
57 |
58 | app.Run();
59 |
60 | class MultiStateStore : IStateStore
61 | {
62 | private readonly string instanceId;
63 |
64 | public MultiStateStore(string instanceId)
65 | {
66 | this.instanceId = instanceId;
67 | }
68 |
69 | // ...
70 | }
71 | ```
72 |
73 | ## Next steps
74 |
75 | - [Learn more about the application environment]({{< ref "dotnet-application-environment" >}})
76 | - [Learn more about multiple services]({{< ref "dotnet-multiple-services" >}})
77 | - Learn more about using the Pluggable Component .NET SDK for:
78 | - [Bindings]({{< ref "dotnet-bindings" >}})
79 | - [Pub/sub]({{< ref "dotnet-pub-sub" >}})
80 | - [State store]({{< ref "dotnet-state-store" >}})
--------------------------------------------------------------------------------
/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-multiple-services.md:
--------------------------------------------------------------------------------
1 | ---
2 | type: docs
3 | title: "Multiple services in a .NET Dapr pluggable component"
4 | linkTitle: "Multiple services"
5 | weight: 1000
6 | description: How to expose multiple services from a .NET pluggable component
7 | no_list: true
8 | is_preview: true
9 | ---
10 |
11 | A pluggable component can host multiple components of varying types. You might do this:
12 | - To minimize the number of sidecars running in a cluster
13 | - To group related components that are likely to share libraries and implementation, such as:
14 | - A database exposed both as a general state store, and
15 | - Output bindings that allow more specific operations.
16 |
17 | Each Unix Domain Socket can manage calls to one component of each type. To host multiple components of the _same_ type, you can spread those types across multiple sockets. The SDK binds each socket to a "service", with each service composed of one or more component types.
18 |
19 | ## Registering multiple services
20 |
21 | Each call to `RegisterService()` binds a socket to a set of registered components, where one of each type of component can be registered per service.
22 |
23 | ```csharp
24 | var app = DaprPluggableComponentsApplication.Create();
25 |
26 | app.RegisterService(
27 | "service-a",
28 | serviceBuilder =>
29 | {
30 | serviceBuilder.RegisterStateStore();
31 | serviceBuilder.RegisterBinding();
32 | });
33 |
34 | app.RegisterService(
35 | "service-b",
36 | serviceBuilder =>
37 | {
38 | serviceBuilder.RegisterStateStore();
39 | });
40 |
41 | app.Run();
42 |
43 | class MyDatabaseStateStore : IStateStore
44 | {
45 | // ...
46 | }
47 |
48 | class MyDatabaseOutputBinding : IOutputBinding
49 | {
50 | // ...
51 | }
52 |
53 | class AnotherStateStore : IStateStore
54 | {
55 | // ...
56 | }
57 | ```
58 |
59 | ## Configuring Multiple Components
60 |
61 | Configuring Dapr to use the hosted components is the same as for any single component - the component YAML refers to the associated socket.
62 |
63 | ```yaml
64 | #
65 | # This component uses the state store associated with socket `state-store-a`
66 | #
67 | apiVersion: dapr.io/v1alpha1
68 | kind: Component
69 | metadata:
70 | name: state-store-a
71 | spec:
72 | type: state.service-a
73 | version: v1
74 | metadata: []
75 | ```
76 |
77 | ```yaml
78 | #
79 | # This component uses the state store associated with socket `state-store-b`
80 | #
81 | apiVersion: dapr.io/v1alpha1
82 | kind: Component
83 | metadata:
84 | name: state-store-b
85 | spec:
86 | type: state.service-b
87 | version: v1
88 | metadata: []
89 | ```
90 |
91 | ## Next steps
92 |
93 | - [Learn more about the component lifetime]({{< ref "dotnet-component-lifetime" >}})
94 | - [Learn more about the application environment]({{< ref "dotnet-application-environment" >}})
95 | - Learn more about using the Pluggable Component .NET SDK for:
96 | - [Bindings]({{< ref "dotnet-bindings" >}})
97 | - [Pub/sub]({{< ref "dotnet-pub-sub" >}})
98 | - [State store]({{< ref "dotnet-state-store" >}})
--------------------------------------------------------------------------------
/samples/AzureStorageQueuesPubSubSample/AzureStorageQueuesPubSubSample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/samples/AzureStorageQueuesPubSubSample/Program.cs:
--------------------------------------------------------------------------------
1 | using Dapr.PluggableComponents;
2 |
3 | var app = DaprPluggableComponentsApplication.Create();
4 |
5 | app.RegisterService(
6 | "azure-storage-queues",
7 | serviceBuilder =>
8 | {
9 | // Use this registration method to have a single pub-sub instance for all components.
10 | // serviceBuilder.RegisterPubSub();
11 |
12 | // This registration method enables a pub-sub instance per component instance.
13 | serviceBuilder.RegisterPubSub(
14 | context =>
15 | {
16 | Console.WriteLine("Creating pub-sub for instance '{0}' on socket '{1}'...", context.InstanceId, context.SocketPath);
17 |
18 | return new AzureStorageQueuesPubSub(context.ServiceProvider.GetRequiredService>());
19 | });
20 | });
21 |
22 | app.Run();
23 |
--------------------------------------------------------------------------------
/samples/AzureStorageQueuesPubSubSample/README.md:
--------------------------------------------------------------------------------
1 | # Azure Storage Queues Pub-Sub Sample
2 |
3 | A Dapr Pluggable Component sample that allows applications to use Azure Storage Queues as a pub-sub component.
4 |
5 | ## Prerequisites
6 |
7 | 1. Create an Azure Storage resource for an Azure subscription in the Azure Portal.
8 | 1. Create a queue within the storage resource.
9 |
10 | ## Configuration
11 |
12 | An application that binds to the component should have a Pluggable Component configuration file that looks like the following:
13 |
14 | ```yaml
15 | apiVersion: dapr.io/v1alpha1
16 | kind: Component
17 | metadata:
18 | name: azure-storage-queues
19 | spec:
20 | type: pubsub.azure-storage-queues
21 | version: v1
22 | metadata:
23 | - name: connectionString
24 | value: ""
25 | - name: queueName
26 | value: ""
27 | - name: pollIntervalSeconds
28 | value:
29 | - name: maxMessages
30 | value:
31 | ```
32 |
33 | The required metadata properties are ``, the connection string for the Azure Storage resource, and ``, the name of the queue to be polled for messages. The `pollIntervalSeconds` and `maxMessages` properties are optional.
34 |
35 | > NOTE: To prevent tokens from being mistakenly committed to a repro, it is best to use Dapr secrets components to store the connection string and then simply reference it from the binding component configuration.
36 |
37 | ## Application
38 |
39 | The application can publish messages to the queue, or subscribe to messages published to the queue, using [HTTP](https://docs.dapr.io/reference/api/pubsub_api/) or the [Dapr Client SDKs](https://docs.dapr.io/developing-applications/sdks/).
--------------------------------------------------------------------------------
/samples/AzureStorageQueuesPubSubSample/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/AzureStorageQueuesPubSubSample/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/samples/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/samples/DiscordBindingSample/DiscordBindingSample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/samples/DiscordBindingSample/Program.cs:
--------------------------------------------------------------------------------
1 | using Dapr.PluggableComponents;
2 |
3 | var app = DaprPluggableComponentsApplication.Create();
4 |
5 | app.RegisterService(
6 | "discord-binding",
7 | serviceBuilder =>
8 | {
9 | // Use this registration method to have a single binding instance for all components.
10 | // serviceBuilder.RegisterBinding();
11 |
12 | // This registration method enables a binding instance per component instance.
13 | serviceBuilder.RegisterBinding(
14 | context =>
15 | {
16 | Console.WriteLine("Creating binding for instance '{0}' on socket '{1}'...", context.InstanceId, context.SocketPath);
17 |
18 | return new DiscordBinding(context.ServiceProvider.GetRequiredService>());
19 | });
20 | });
21 |
22 | app.Run();
23 |
--------------------------------------------------------------------------------
/samples/DiscordBindingSample/README.md:
--------------------------------------------------------------------------------
1 | # Discord Binding Sample
2 |
3 | A Dapr Pluggable Component sample that allows applications to bind to Discord and send and receive messages.
4 |
5 | ## Prerequisites
6 |
7 | ### Create a Discord Application and Bot
8 |
9 | The bindings in this sample are exposed within Discord as an "application bot". This README will not replicate the comprehensive Discord documentation for creation of a bot available [here](https://discord.com/developers/docs/intro).
10 |
11 | ### Create a Discord Test Server
12 |
13 | It is recommended that developers test application bots on a test (i.e. personal) Discord server; specific instructions are [here](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-).
14 |
15 | ### Install the Application Bot on the Test Server
16 |
17 | You can use the Discord Developer Portal's OAuth2::URL Generator to generate a URL that installs the application bot on the test server. More instructions are [here](),https://discord.com/developers/docs/getting-started#installing-your-app.
18 |
19 | > NOTE: This sample requires the bot to have the `bot` scope and `Read Messages/View Channels` and `Send Messages` bot permissions on any associated server.
20 |
21 | ## Configuration
22 |
23 | An application that binds to the component should have a Pluggable Component configuration file that looks like the following:
24 |
25 | ```yaml
26 | apiVersion: dapr.io/v1alpha1
27 | kind: Component
28 | metadata:
29 | name: discord-binding
30 | spec:
31 | type: bindings.discord-binding
32 | version: v1
33 | metadata:
34 | - name: token
35 | value: ""
36 | ```
37 |
38 | > NOTE: To prevent tokens from being mistakenly committed to a repro, it is best to use Dapr secrets components to store the token and then simply reference it from the binding component configuration.
39 |
40 | ## Application
41 |
42 | The application can send messages to Discord, using HTTP or the Dapr Client SDK, by invoking the `SendMessage` operation of the output binding with JSON data:
43 |
44 | ```json
45 | {
46 | "channelId": "",
47 | "content": ""
48 | }
49 | ```
50 |
51 | An example HTTP request would look like:
52 |
53 | `POST http://localhost:/v1.0/bindings/discord-binding`
54 |
55 | ```json
56 | {
57 | "data": {
58 | "channelId": "1234567890123456789",
59 | "content": "Hello world from Dapr!"
60 | },
61 | "operation": "SendMessage"
62 | }
63 | ```
64 |
65 | >NOTE: The channel ID can be found by [enabling developer mode](https://discord.com/developers/docs/game-sdk/store#application-test-mode) in Discord, right-clicking the channel name, and selecting `Copy ID` from the context menu.
66 |
67 | The application can read messages sent to Discord by exposing a `POST` route that matches the binding name (i.e. `discord-binding`), and accepts a JSON body of the form:
68 |
69 | ```json
70 | {
71 | "channelId": "",
72 | "content": ""
73 | }
74 | ```
75 |
--------------------------------------------------------------------------------
/samples/DiscordBindingSample/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/DiscordBindingSample/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/samples/MemoryStateStoreSample/MemoryStateStoreSample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/samples/MemoryStateStoreSample/Program.cs:
--------------------------------------------------------------------------------
1 | using MemoryStateStoreSample.Services;
2 |
3 | var app = DaprPluggableComponentsApplication.Create();
4 |
5 | app.RegisterService(
6 | "memstore",
7 | serviceBuilder =>
8 | {
9 | // Use this registration method to have a single state store instance for all components.
10 | // serviceBuilder.RegisterStateStore();
11 |
12 | // This registration method enables a state store instance per component instance.
13 | serviceBuilder.RegisterStateStore(
14 | context =>
15 | {
16 | Console.WriteLine("Creating state store for instance '{0}' on socket '{1}'...", context.InstanceId, context.SocketPath);
17 |
18 | return new MemoryStateStore(context.ServiceProvider.GetRequiredService>());
19 | });
20 | });
21 |
22 | app.Run();
23 |
--------------------------------------------------------------------------------
/samples/MemoryStateStoreSample/Services/MemoryStateStore.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Concurrent;
2 | using System.Text;
3 | using Dapr.PluggableComponents.Components;
4 |
5 | namespace MemoryStateStoreSample.Services;
6 |
7 | internal sealed class MemoryStateStore : IStateStore
8 | {
9 | private readonly ILogger logger;
10 |
11 | private readonly IDictionary storage = new ConcurrentDictionary();
12 |
13 | public MemoryStateStore(ILogger logger)
14 | {
15 | this.logger = logger;
16 | }
17 |
18 | #region IStateStore Members
19 |
20 | public Task DeleteAsync(StateStoreDeleteRequest request, CancellationToken cancellationToken = default)
21 | {
22 | this.logger.LogInformation("Delete request for key {key}", request.Key);
23 |
24 | this.storage.Remove(request.Key);
25 |
26 | return Task.CompletedTask;
27 | }
28 |
29 | public Task GetAsync(StateStoreGetRequest request, CancellationToken cancellationToken = default)
30 | {
31 | this.logger.LogInformation("Get request for key {key}", request.Key);
32 |
33 | StateStoreGetResponse? response = null;
34 |
35 | if (this.storage.TryGetValue(request.Key, out var data))
36 | {
37 | response = new StateStoreGetResponse
38 | {
39 | Data = Encoding.UTF8.GetBytes(data)
40 | };
41 | }
42 |
43 | return Task.FromResult(response);
44 | }
45 |
46 | public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default)
47 | {
48 | return Task.CompletedTask;
49 | }
50 |
51 | public Task SetAsync(StateStoreSetRequest request, CancellationToken cancellationToken = default)
52 | {
53 | this.logger.LogInformation("Set request for key {key}", request.Key);
54 |
55 | this.storage[request.Key] = Encoding.UTF8.GetString(request.Value.Span);
56 |
57 | return Task.CompletedTask;
58 | }
59 |
60 | #endregion
61 | }
62 |
--------------------------------------------------------------------------------
/samples/MemoryStateStoreSample/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/MemoryStateStoreSample/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.AspNetCore/Dapr.PluggableComponents.AspNetCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | This package contains the reference assemblies for hosting pluggable components for Dapr.
9 | $(PackageTags);
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | True
29 | True
30 | Resources.resx
31 |
32 |
33 |
34 |
35 |
36 | ResXFileCodeGenerator
37 | Resources.Designer.cs
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.AspNetCore/DaprPluggableComponentsServiceOptions.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | namespace Dapr.PluggableComponents;
15 |
16 | ///
17 | /// Represents options related to the socket file associated with a service.
18 | ///
19 | /// Gets or sets the name of the socket.
20 | public sealed record DaprPluggableComponentsServiceOptions(string SocketName)
21 | {
22 | ///
23 | /// Gets or sets the extension added to the socket file name.
24 | ///
25 | ///
26 | /// If omitted and not specified by the environment
27 | /// variable, the default extension will be used.
28 | ///
29 | public string? SocketExtension { get; init; }
30 |
31 | ///
32 | /// Gets or sets the folder in which the socket file is created.
33 | ///
34 | ///
35 | /// If omitted and not specified by the environment
36 | /// variable, the default folder will be used.
37 | ///
38 | public string? SocketFolder { get; init; }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.AspNetCore/IDaprPluggableComponentsRegistrar.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | namespace Dapr.PluggableComponents;
15 |
16 | internal interface IDaprPluggableComponentsRegistrar
17 | {
18 | void RegisterAdaptor() where TAdaptor : class;
19 |
20 | void RegisterComponent(string socketPath) where TComponent : class;
21 |
22 | void RegisterComponent(string socketPath, ComponentProviderDelegate componentFactory) where TComponent : class;
23 |
24 | void RegisterProvider(string socketPath)
25 | where TComponent : class
26 | where TComponentImpl : class;
27 | }
28 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.AspNetCore/MultiplexedComponentProvider.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using System.Collections.Concurrent;
15 | using Dapr.PluggableComponents.Adaptors;
16 | using Grpc.Core;
17 |
18 | namespace Dapr.PluggableComponents;
19 |
20 | internal sealed class MultiplexedComponentProvider : IDaprPluggableComponentProvider
21 | {
22 | private const string MetadataInstanceId = "x-component-instance";
23 |
24 | private readonly ComponentProviderDelegate componentProvider;
25 | private readonly ConcurrentDictionary> components = new ConcurrentDictionary>();
26 | private readonly Lazy defaultComponent;
27 | private readonly ComponentProviderContext defaultComponentProviderContext;
28 |
29 | public MultiplexedComponentProvider(ComponentProviderDelegate componentProvider, IServiceProvider serviceProvider, string socketPath)
30 | {
31 | this.componentProvider = componentProvider ?? throw new ArgumentNullException(nameof(componentProvider));
32 |
33 | this.defaultComponentProviderContext = new ComponentProviderContext(
34 | null,
35 | serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)),
36 | socketPath ?? throw new ArgumentNullException(nameof(socketPath)));
37 |
38 | this.defaultComponent = new Lazy(() => componentProvider(this.defaultComponentProviderContext));
39 | }
40 |
41 | #region IDaprPluggableComponentProvider Members
42 |
43 | public T GetComponent(ServerCallContext context)
44 | {
45 | var entry = context.RequestHeaders.Get(MetadataInstanceId);
46 |
47 | var component =
48 | entry != null
49 | ? this.components.GetOrAdd(entry.Value, instanceId => new Lazy(() => this.componentProvider(this.defaultComponentProviderContext with { InstanceId = instanceId })))
50 | : this.defaultComponent;
51 |
52 | return component.Value;
53 | }
54 |
55 | #endregion
56 | }
57 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.AspNetCore/RegisteredComponentProvider.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using System.Globalization;
15 | using Dapr.PluggableComponents.Adaptors;
16 | using Dapr.PluggableComponents.AspNetCore;
17 | using Grpc.Core;
18 | using Microsoft.AspNetCore.Connections.Features;
19 |
20 | namespace Dapr.PluggableComponents;
21 |
22 | internal sealed class RegisteredComponentProvider : IDaprPluggableComponentProvider
23 | {
24 | private readonly DaprPluggableComponentsRegistry registry;
25 | private readonly IServiceProvider serviceProvider;
26 |
27 | public RegisteredComponentProvider(DaprPluggableComponentsRegistry registry, IServiceProvider serviceProvider)
28 | {
29 | ArgumentNullException.ThrowIfNull(registry);
30 | ArgumentNullException.ThrowIfNull(serviceProvider);
31 |
32 | this.registry = registry;
33 | this.serviceProvider = serviceProvider;
34 | }
35 |
36 | public TComponent GetComponent(ServerCallContext context)
37 | {
38 | string socketPath = GetSocketPath(context);
39 |
40 | var componentProvider = this.registry.GetComponentProvider(this.serviceProvider, socketPath)
41 | ?? throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.RegisteredComponentProviderNoProviderMessage, typeof(TComponent)));
42 |
43 | return componentProvider.GetComponent(context);
44 | }
45 |
46 | private static string GetSocketPath(ServerCallContext context)
47 | {
48 | var httpContext = context.GetHttpContext();
49 | var socketFeature = httpContext.Features.Get();
50 | var socketPath = socketFeature?.Socket.LocalEndPoint?.ToString() ?? throw new InvalidOperationException(Resources.RegisteredComponentProviderUnknownSocketMessage);
51 |
52 | return socketPath;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.AspNetCore/WebApplicationExtensions.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using Microsoft.AspNetCore.Builder;
15 | using Microsoft.AspNetCore.Routing;
16 |
17 | namespace Dapr.PluggableComponents;
18 |
19 | ///
20 | /// Represents extension methods for registering Dapr Pluggable Component related services with instances.
21 | ///
22 | public static class WebApplicationExtensions
23 | {
24 | ///
25 | /// Maps services needed to host Dapr Pluggable Components via an ASP.NET application.
26 | ///
27 | /// The type of ASP.NET endpoint builder.
28 | /// An ASP.NET endpoint builder.
29 | /// The current builder instance.
30 | public static TBuilder MapDaprPluggableComponentsSupportServices(this TBuilder app)
31 | where TBuilder : IEndpointRouteBuilder
32 | {
33 | // Dapr component discovery relies on the gRPC reflection service.
34 | app.MapGrpcReflectionService();
35 |
36 | return app;
37 | }
38 |
39 | ///
40 | /// Maps a gRPC "adaptor" service through which Dapr Pluggable Component calls are made.
41 | ///
42 | /// The type of gRPC service.
43 | /// An ASP.NET endpoint builder.
44 | /// A through which the service can be further configured.
45 | public static GrpcServiceEndpointConventionBuilder MapDaprPluggableComponentAdaptor(this IEndpointRouteBuilder app)
46 | where T : class
47 | {
48 | return app.MapGrpcService();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Protos/Dapr.PluggableComponents.Protos.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | v1
5 | v1.11.0
6 | https://raw.githubusercontent.com/dapr/dapr/$(ProtosTag)/dapr/proto/components/$(ProtosVersion)
7 | $(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework)\Protos
8 | $(ProtosRootDir)\dapr\proto\components\$(ProtosVersion)
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | This package contains the gRPC generated types for developing pluggable components for Dapr.
21 | $(PackageTags);
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | runtime; build; native; contentfiles; analyzers; buildtransitive
34 | all
35 |
36 |
37 |
38 |
39 |
41 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Adaptors/AsyncStreamReader.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using System.Threading.Channels;
15 | using Grpc.Core;
16 |
17 | namespace Dapr.PluggableComponents.Adaptors;
18 |
19 | internal sealed class AsyncStreamReader : IAsyncStreamReader
20 | where TRequest : class
21 | {
22 | private readonly Channel channel = Channel.CreateUnbounded();
23 | private TRequest? current;
24 |
25 | public ValueTask AddAsync(TRequest request, CancellationToken cancellationToken = default)
26 | {
27 | return this.channel.Writer.WriteAsync(request, cancellationToken);
28 | }
29 |
30 | public void Complete()
31 | {
32 | this.channel.Writer.Complete();
33 | }
34 |
35 | #region IAsyncStreamReader Members
36 |
37 | public TRequest Current => this.current ?? throw new InvalidOperationException();
38 |
39 | public async Task MoveNext(CancellationToken cancellationToken)
40 | {
41 | var result = await this.channel.Reader.WaitToReadAsync(cancellationToken);
42 |
43 | if (result && this.channel.Reader.TryRead(out this.current))
44 | {
45 | return true;
46 | }
47 |
48 | this.current = null;
49 |
50 | return false;
51 | }
52 |
53 | #endregion
54 | }
55 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Adaptors/OutputBindingAdaptorTests.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using Dapr.Client.Autogen.Grpc.v1;
15 | using Dapr.PluggableComponents.Components.Bindings;
16 | using Dapr.Proto.Components.V1;
17 | using NSubstitute;
18 | using Xunit;
19 |
20 | namespace Dapr.PluggableComponents.Adaptors;
21 |
22 | public sealed class OutputBindignAdaptorTests
23 | {
24 | [Fact]
25 | public Task InitTests()
26 | {
27 | return AdaptorFixture.TestInitAsync(
28 | () => AdaptorFixture.CreateOutputBinding(),
29 | (fixture, metadataRequest) => fixture.Adaptor.Init(new Proto.Components.V1.OutputBindingInitRequest { Metadata = metadataRequest }, fixture.Context));
30 | }
31 |
32 | [Fact]
33 | public Task PingTests()
34 | {
35 | return AdaptorFixture.TestPingAsync(
36 | AdaptorFixture.CreateOutputBinding,
37 | fixture => fixture.Adaptor.Ping(new PingRequest(), fixture.Context));
38 | }
39 |
40 | [Fact]
41 | public async Task InvokeTests()
42 | {
43 | using var fixture = AdaptorFixture.CreateOutputBinding();
44 |
45 | string operation = "operation";
46 | string contentType = "application/json";
47 |
48 | var request = new InvokeRequest { Operation = operation };
49 |
50 | fixture.MockComponent
51 | .InvokeAsync(Arg.Is(request => request.Operation == operation), Arg.Is(token => token == fixture.Context.CancellationToken))
52 | .Returns(new OutputBindingInvokeResponse { ContentType = contentType });
53 |
54 | var response = await fixture.Adaptor.Invoke(new InvokeRequest { Operation = operation }, fixture.Context);
55 |
56 | Assert.Equal(contentType, response.ContentType);
57 |
58 | await fixture.MockComponent
59 | .Received(1)
60 | .InvokeAsync(Arg.Is(request => request.Operation == operation), Arg.Is(token => token == fixture.Context.CancellationToken));
61 | }
62 |
63 | [Fact]
64 | public async Task ListOperationsTests()
65 | {
66 | using var fixture = AdaptorFixture.CreateOutputBinding();
67 |
68 | var operations = new[] { "operation1", "operation2" };
69 |
70 | fixture.MockComponent
71 | .ListOperationsAsync(Arg.Is(token => token == fixture.Context.CancellationToken))
72 | .Returns(operations);
73 |
74 | var response = await fixture.Adaptor.ListOperations(new ListOperationsRequest(), fixture.Context);
75 |
76 | Assert.Equal(operations, response.Operations);
77 |
78 | await fixture.MockComponent
79 | .Received(1)
80 | .ListOperationsAsync(Arg.Is(token => token == fixture.Context.CancellationToken));
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Adaptors/TestServerCallContext.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using Grpc.Core;
15 |
16 | namespace Dapr.PluggableComponents.Adaptors;
17 |
18 | internal sealed class TestServerCallContext : ServerCallContext, IDisposable
19 | {
20 | private readonly CancellationTokenSource cts = new CancellationTokenSource();
21 |
22 | public void Cancel()
23 | {
24 | this.cts.Cancel();
25 | }
26 |
27 | #region ServerCallContext Overrides
28 |
29 | protected override string MethodCore => throw new NotImplementedException();
30 |
31 | protected override string HostCore => throw new NotImplementedException();
32 |
33 | protected override string PeerCore => throw new NotImplementedException();
34 |
35 | protected override DateTime DeadlineCore => throw new NotImplementedException();
36 |
37 | protected override Metadata RequestHeadersCore => throw new NotImplementedException();
38 |
39 | protected override CancellationToken CancellationTokenCore => this.cts.Token;
40 |
41 | protected override Metadata ResponseTrailersCore => throw new NotImplementedException();
42 |
43 | protected override Status StatusCore { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
44 |
45 | protected override WriteOptions? WriteOptionsCore { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
46 |
47 | protected override AuthContext AuthContextCore => throw new NotImplementedException();
48 |
49 | protected override ContextPropagationToken CreatePropagationTokenCore(ContextPropagationOptions? options)
50 | {
51 | throw new NotImplementedException();
52 | }
53 |
54 | protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders)
55 | {
56 | throw new NotImplementedException();
57 | }
58 |
59 | #endregion
60 |
61 | #region IDisposable Members
62 |
63 | public void Dispose()
64 | {
65 | this.cts.Dispose();
66 | }
67 |
68 | #endregion
69 | }
70 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Adaptors/TransactionalStateStoreAdaptorTests.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using Dapr.PluggableComponents.Adaptors;
15 | using Dapr.Proto.Components.V1;
16 | using Grpc.Core;
17 | using Microsoft.Extensions.Logging;
18 | using NSubstitute;
19 | using Xunit;
20 |
21 | namespace Dapr.PluggableComponents.Components.StateStore;
22 |
23 | public sealed class TransactionalStateStoreAdaptorTests
24 | {
25 | [Fact]
26 | public async Task TransactTest()
27 | {
28 | var mockStateStore = Substitute.For();
29 |
30 | mockStateStore
31 | .TransactAsync(Arg.Any(), Arg.Any())
32 | .Returns(Task.CompletedTask);
33 |
34 | var logger = Substitute.For>();
35 |
36 | var mockComponentProvider = Substitute.For>();
37 |
38 | mockComponentProvider
39 | .GetComponent(Arg.Any())
40 | .Returns(mockStateStore);
41 |
42 | var adaptor = new TransactionalStateStoreAdaptor(logger, mockComponentProvider);
43 |
44 | using var context = new TestServerCallContext();
45 |
46 | var grpcRequest = new TransactionalStateRequest();
47 |
48 | grpcRequest.Metadata.Add("key", "value");
49 |
50 | await adaptor.Transact(grpcRequest, context);
51 |
52 | await mockStateStore
53 | .Received(1)
54 | .TransactAsync(Arg.Is(request => AssertMetadataEqual(grpcRequest.Metadata, request.Metadata)), Arg.Is(cancellationToken => cancellationToken == context.CancellationToken));
55 | }
56 |
57 | private static bool AssertMetadataEqual(IReadOnlyDictionary expected, IReadOnlyDictionary actual)
58 | {
59 | Assert.Equal(expected, actual);
60 |
61 | return true;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using System.Runtime.CompilerServices;
15 |
16 | [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
17 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/Bindings/InputBindingReadRequestTests.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using Dapr.Proto.Components.V1;
15 | using Google.Protobuf;
16 | using Xunit;
17 |
18 | namespace Dapr.PluggableComponents.Components.Bindings;
19 |
20 | public sealed class InputBindingReadRequestTests
21 | {
22 | [Fact]
23 | public void FromReadRequestTests()
24 | {
25 | ConversionAssert.StringEqual(
26 | messageId => new ReadRequest { MessageId = messageId },
27 | InputBindingReadRequest.FromReadRequest,
28 | request => request.MessageId);
29 |
30 | ConversionAssert.DataEqual(
31 | responseData => new ReadRequest { ResponseData = ByteString.CopyFrom(responseData) },
32 | InputBindingReadRequest.FromReadRequest,
33 | request => request.ResponseData.Span.ToArray());
34 |
35 | ConversionAssert.Equal(
36 | responseError => new ReadRequest { ResponseError = responseError },
37 | (_, request) => InputBindingReadRequest.FromReadRequest(request),
38 | request => request.ResponseErrorMessage,
39 | new (AckResponseError?, string?)[]
40 | {
41 | (null, null),
42 | (new AckResponseError(), ""),
43 | (new AckResponseError { Message = "" }, ""),
44 | (new AckResponseError { Message = "message" }, "message")
45 | });
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/Bindings/InputBindingReadResponseTests.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using Xunit;
15 |
16 | namespace Dapr.PluggableComponents.Components.Bindings;
17 |
18 | public sealed class InputBindingReadResponseTests
19 | {
20 | [Fact]
21 | public void ToReadResponseTests()
22 | {
23 | ConversionAssert.ContentTypeEqual(
24 | contentType => new InputBindingReadResponse { ContentType = contentType },
25 | response => InputBindingReadResponse.ToReadResponse("messageId", response),
26 | response => response.ContentType);
27 |
28 | ConversionAssert.DataEqual(
29 | data => new InputBindingReadResponse { Data = data },
30 | response => InputBindingReadResponse.ToReadResponse("messageId", response),
31 | response => response.Data.Span.ToArray());
32 |
33 | ConversionAssert.StringEqual(
34 | messageId => new InputBindingReadResponse(),
35 | (messageId, response) => InputBindingReadResponse.ToReadResponse(messageId, response),
36 | response => response.MessageId);
37 |
38 | ConversionAssert.MetadataEqual(
39 | metadata => new InputBindingReadResponse { Metadata = metadata },
40 | response => InputBindingReadResponse.ToReadResponse("messageId", response),
41 | response => response.Metadata);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/Bindings/MockCombinedBinding.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | namespace Dapr.PluggableComponents.Components.Bindings;
15 |
16 | internal interface IMockCombinedBinding : IMockPluggableComponent, IInputBinding, IOutputBinding where T : class
17 | {
18 | }
19 |
20 | internal sealed class MockCombinedBinding : IInputBinding, IOutputBinding where T : class
21 | {
22 | private readonly IMockCombinedBinding proxy;
23 |
24 | public MockCombinedBinding(IMockCombinedBinding proxy)
25 | {
26 | this.proxy = proxy;
27 |
28 | this.proxy.Create();
29 | }
30 |
31 | #region IPluggableComponent Members
32 |
33 | public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default)
34 | {
35 | return this.proxy.InitAsync(request, cancellationToken);
36 | }
37 |
38 | #endregion
39 |
40 | #region IInputBinding Members
41 |
42 | public Task ReadAsync(MessageDeliveryHandler deliveryHandler, CancellationToken cancellationToken = default)
43 | {
44 | return this.proxy.ReadAsync(deliveryHandler, cancellationToken);
45 | }
46 |
47 | #endregion
48 |
49 | #region IOutputBinding Members
50 |
51 | public Task InvokeAsync(OutputBindingInvokeRequest request, CancellationToken cancellationToken = default)
52 | {
53 | return this.proxy.InvokeAsync(request, cancellationToken);
54 | }
55 |
56 | public Task ListOperationsAsync(CancellationToken cancellationToken = default)
57 | {
58 | return this.proxy.ListOperationsAsync(cancellationToken);
59 | }
60 |
61 | #endregion
62 | }
63 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/Bindings/MockInputBinding.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | namespace Dapr.PluggableComponents.Components.Bindings;
15 |
16 | internal interface IMockInputBinding : IMockPluggableComponent, IInputBinding where T : class
17 | {
18 | }
19 |
20 | internal sealed class MockInputBinding : IInputBinding where T : class
21 | {
22 | private readonly IMockInputBinding proxy;
23 |
24 | public MockInputBinding(IMockInputBinding proxy)
25 | {
26 | this.proxy = proxy;
27 |
28 | this.proxy.Create();
29 | }
30 |
31 | #region IInputBinding Members
32 |
33 | public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default)
34 | {
35 | return this.proxy.InitAsync(request, cancellationToken);
36 | }
37 |
38 | public Task ReadAsync(MessageDeliveryHandler deliveryHandler, CancellationToken cancellationToken = default)
39 | {
40 | return this.proxy.ReadAsync(deliveryHandler, cancellationToken);
41 | }
42 |
43 | #endregion
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/Bindings/MockOutputBinding.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | namespace Dapr.PluggableComponents.Components.Bindings;
15 |
16 | internal interface IMockOutputBinding : IMockPluggableComponent, IOutputBinding where T : class
17 | {
18 | }
19 |
20 | internal sealed class MockOutputBinding : IOutputBinding where T : class
21 | {
22 | private readonly IMockOutputBinding proxy;
23 |
24 | public MockOutputBinding(IMockOutputBinding proxy)
25 | {
26 | this.proxy = proxy;
27 |
28 | this.proxy.Create();
29 | }
30 |
31 | #region IOutputBinding Members
32 |
33 | public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default)
34 | {
35 | return this.proxy.InitAsync(request, cancellationToken);
36 | }
37 |
38 | public Task InvokeAsync(OutputBindingInvokeRequest request, CancellationToken cancellationToken = default)
39 | {
40 | return this.proxy.InvokeAsync(request, cancellationToken);
41 | }
42 |
43 | public Task ListOperationsAsync(CancellationToken cancellationToken = default)
44 | {
45 | return this.proxy.ListOperationsAsync(cancellationToken);
46 | }
47 |
48 | #endregion
49 | }
50 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/Bindings/OutputBindingInvokeRequestTests.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using Dapr.PluggableComponents.Utilities;
15 | using Dapr.Proto.Components.V1;
16 | using Google.Protobuf;
17 | using Xunit;
18 |
19 | namespace Dapr.PluggableComponents.Components.Bindings;
20 |
21 | public sealed class OutputBindingInvokeRequestTests
22 | {
23 | [Fact]
24 | public void FromInvokeRequestTests()
25 | {
26 | ConversionAssert.DataEqual(
27 | data => new InvokeRequest { Data = ByteString.CopyFrom(data) },
28 | OutputBindingInvokeRequest.FromInvokeRequest,
29 | request => request.Data.Span.ToArray());
30 |
31 | ConversionAssert.MetadataEqual(
32 | metadata =>
33 | {
34 | var request = new InvokeRequest();
35 |
36 | request.Metadata.Add(metadata);
37 |
38 | return request;
39 | },
40 | OutputBindingInvokeRequest.FromInvokeRequest,
41 | request => request.Metadata);
42 |
43 | ConversionAssert.StringEqual(
44 | operation => new InvokeRequest { Operation = operation },
45 | OutputBindingInvokeRequest.FromInvokeRequest,
46 | request => request.Operation);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/Bindings/OutputBindingInvokeResponseTests.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using Xunit;
15 |
16 | namespace Dapr.PluggableComponents.Components.Bindings;
17 |
18 | public sealed class OutputBindingInvokeResponseTests
19 | {
20 | [Fact]
21 | public void ToInvokeResponseTests()
22 | {
23 | ConversionAssert.ContentTypeEqual(
24 | contentType => new OutputBindingInvokeResponse { ContentType = contentType },
25 | response => OutputBindingInvokeResponse.ToInvokeResponse(response),
26 | response => response.ContentType);
27 |
28 | ConversionAssert.DataEqual(
29 | data => new OutputBindingInvokeResponse { Data = data },
30 | response => OutputBindingInvokeResponse.ToInvokeResponse(response),
31 | response => response.Data.Span.ToArray());
32 |
33 | ConversionAssert.MetadataEqual(
34 | metadata => new OutputBindingInvokeResponse { Metadata = metadata },
35 | response => OutputBindingInvokeResponse.ToInvokeResponse(response),
36 | response => response.Metadata);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/IMockPluggableComponent.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | namespace Dapr.PluggableComponents.Components;
15 |
16 | internal interface IMockPluggableComponent : IPluggableComponent
17 | {
18 | void Create();
19 | }
20 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/PubSub/MockPubSub.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | namespace Dapr.PluggableComponents.Components.PubSub;
15 |
16 | internal interface IMockPubSub : IMockPluggableComponent, IPubSub where T : class
17 | {
18 | }
19 |
20 | internal sealed class MockPubSub : IPubSub where T : class
21 | {
22 | private readonly IMockPubSub proxy;
23 |
24 | public MockPubSub(IMockPubSub proxy)
25 | {
26 | this.proxy = proxy;
27 |
28 | this.proxy.Create();
29 | }
30 |
31 | #region IPubSub Members
32 |
33 | public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default)
34 | {
35 | return this.proxy.InitAsync(request, cancellationToken);
36 | }
37 |
38 | public Task PublishAsync(PubSubPublishRequest request, CancellationToken cancellationToken = default)
39 | {
40 | return this.proxy.PublishAsync(request, cancellationToken);
41 | }
42 |
43 | public Task PullMessagesAsync(PubSubPullMessagesTopic topic, MessageDeliveryHandler deliveryHandler, CancellationToken cancellationToken = default)
44 | {
45 | return this.proxy.PullMessagesAsync(topic, deliveryHandler, cancellationToken);
46 | }
47 |
48 | #endregion
49 | }
50 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/PubSub/PubSubPublishRequestTests.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using Dapr.PluggableComponents.Utilities;
15 | using Dapr.Proto.Components.V1;
16 | using Google.Protobuf;
17 | using Xunit;
18 |
19 | namespace Dapr.PluggableComponents.Components.PubSub;
20 |
21 | public sealed class PubSubPublishRequestTests
22 | {
23 | [Fact]
24 | public void FromPublishRequestTests()
25 | {
26 | // NOTE: Conversion from gRPC request content type is not symmetric with the reverse,
27 | // so one cannot use the ConversionAssert.ContentTypeEqual() method.
28 | ConversionAssert.Equal(
29 | contentType => new PublishRequest { ContentType = contentType },
30 | (_, request) => PubSubPublishRequest.FromPublishRequest(request),
31 | request => request.ContentType,
32 | new (string, string?)[]
33 | {
34 | ("", ""),
35 | ("application/json", "application/json")
36 | });
37 |
38 | ConversionAssert.DataEqual(
39 | data => new PublishRequest { Data = ByteString.CopyFrom(data) },
40 | request => PubSubPublishRequest.FromPublishRequest(request),
41 | request => request.Data.ToArray());
42 |
43 | ConversionAssert.MetadataEqual(
44 | metadata =>
45 | {
46 | var request = new PublishRequest();
47 |
48 | request.Metadata.Add(metadata);
49 |
50 | return request;
51 | },
52 | request => PubSubPublishRequest.FromPublishRequest(request),
53 | request => request.Metadata);
54 |
55 | ConversionAssert.StringEqual(
56 | pubSubName => new PublishRequest { PubsubName = pubSubName },
57 | request => PubSubPublishRequest.FromPublishRequest(request),
58 | request => request.PubSubName);
59 |
60 | ConversionAssert.StringEqual(
61 | topic => new PublishRequest { Topic = topic },
62 | request => PubSubPublishRequest.FromPublishRequest(request),
63 | request => request.Topic);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/PubSub/PubSubPullMessagesResponseTests.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using Xunit;
15 |
16 | namespace Dapr.PluggableComponents.Components.PubSub;
17 |
18 | public sealed class PubSubPullMessagesResponseTests
19 | {
20 | [Fact]
21 | public void ToPullMessagesResponseTests()
22 | {
23 | ConversionAssert.ContentTypeEqual(
24 | contentType => new PubSubPullMessagesResponse("topic") { ContentType = contentType },
25 | response => PubSubPullMessagesResponse.ToPullMessagesResponse("id", response),
26 | response => response.ContentType);
27 |
28 | ConversionAssert.DataEqual(
29 | data => new PubSubPullMessagesResponse("topic") { Data = data },
30 | response => PubSubPullMessagesResponse.ToPullMessagesResponse("id", response),
31 | response => response.Data);
32 |
33 | ConversionAssert.MetadataEqual(
34 | metadata => new PubSubPullMessagesResponse("topic") { Metadata = metadata },
35 | response => PubSubPullMessagesResponse.ToPullMessagesResponse("id", response),
36 | response => response.Metadata);
37 |
38 | ConversionAssert.StringEqual(
39 | _ => new PubSubPullMessagesResponse("topic"),
40 | (id, response) => PubSubPullMessagesResponse.ToPullMessagesResponse(id, response),
41 | response => response.Id);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/PubSub/PubSubPullMessagesTopicTests.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using Dapr.PluggableComponents.Utilities;
15 | using Dapr.Proto.Components.V1;
16 | using Xunit;
17 |
18 | namespace Dapr.PluggableComponents.Components.PubSub;
19 |
20 | public sealed class PubSubPullMessagesTopicTests
21 | {
22 | [Fact]
23 | public void FromTopicTests()
24 | {
25 | ConversionAssert.MetadataEqual(
26 | metadata =>
27 | {
28 | var topic = new Topic();
29 |
30 | topic.Metadata.Add(metadata);
31 |
32 | return topic;
33 | },
34 | PubSubPullMessagesTopic.FromTopic,
35 | topic => topic.Metadata);
36 |
37 | ConversionAssert.StringEqual(
38 | name => new Topic { Name = name },
39 | PubSubPullMessagesTopic.FromTopic,
40 | topic => topic.Name);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/StateStore/MockBulkStateStore.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | namespace Dapr.PluggableComponents.Components.StateStore;
15 |
16 | internal interface IMockBulkStateStore : IMockStateStore, IBulkStateStore where T : class
17 | {
18 | }
19 |
20 | internal sealed class MockBulkStateStore : MockStateStore, IBulkStateStore where T : class
21 | {
22 | private readonly IMockBulkStateStore proxy;
23 |
24 | public MockBulkStateStore(IMockBulkStateStore proxy)
25 | : base(proxy)
26 | {
27 | this.proxy = proxy;
28 | }
29 |
30 | #region IBulkStateStore Members
31 |
32 | public Task BulkDeleteAsync(StateStoreDeleteRequest[] requests, CancellationToken cancellationToken = default)
33 | {
34 | return this.proxy.BulkDeleteAsync(requests, cancellationToken);
35 | }
36 |
37 | public Task BulkGetAsync(StateStoreGetRequest[] requests, CancellationToken cancellationToken = default)
38 | {
39 | return this.proxy.BulkGetAsync(requests, cancellationToken);
40 | }
41 |
42 | public Task BulkSetAsync(StateStoreSetRequest[] requests, CancellationToken cancellationToken = default)
43 | {
44 | return this.proxy.BulkSetAsync(requests, cancellationToken);
45 | }
46 |
47 | #endregion
48 | }
49 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/StateStore/MockQueryableStateStore.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | namespace Dapr.PluggableComponents.Components.StateStore;
15 |
16 | internal interface IMockQueryableStateStore : IMockStateStore, IQueryableStateStore where T : class
17 | {
18 | }
19 |
20 | internal sealed class MockQueryableStateStore : MockStateStore, IQueryableStateStore where T : class
21 | {
22 | private readonly IMockQueryableStateStore proxy;
23 |
24 | public MockQueryableStateStore(IMockQueryableStateStore proxy)
25 | : base(proxy)
26 | {
27 | this.proxy = proxy;
28 | }
29 |
30 | #region IQueryableMockStateStore Members
31 |
32 | public Task QueryAsync(StateStoreQueryRequest request, CancellationToken cancellationToken = default)
33 | {
34 | return this.proxy.QueryAsync(request, cancellationToken);
35 | }
36 |
37 | #endregion
38 | }
39 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/StateStore/MockStateStore.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | namespace Dapr.PluggableComponents.Components.StateStore;
15 |
16 | internal interface IMockStateStore : IMockPluggableComponent, IStateStore where T : class
17 | {
18 | }
19 |
20 | internal class MockStateStore : IStateStore where T : class
21 | {
22 | private readonly IMockStateStore proxy;
23 |
24 | public MockStateStore(IMockStateStore proxy)
25 | {
26 | this.proxy = proxy;
27 |
28 | this.proxy.Create();
29 | }
30 |
31 | #region IStateStore Members
32 |
33 | public Task DeleteAsync(StateStoreDeleteRequest request, CancellationToken cancellationToken = default)
34 | {
35 | return this.proxy.DeleteAsync(request, cancellationToken);
36 | }
37 |
38 | public Task GetAsync(StateStoreGetRequest request, CancellationToken cancellationToken = default)
39 | {
40 | return this.proxy.GetAsync(request, cancellationToken);
41 | }
42 |
43 | public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default)
44 | {
45 | return this.proxy.InitAsync(request, cancellationToken);
46 | }
47 |
48 | public Task SetAsync(StateStoreSetRequest request, CancellationToken cancellationToken = default)
49 | {
50 | return this.proxy.SetAsync(request, cancellationToken);
51 | }
52 |
53 | #endregion
54 | }
55 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/StateStore/MockTransactionalStateStore.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | namespace Dapr.PluggableComponents.Components.StateStore;
15 |
16 | internal interface IMockTransactionalStateStore : IMockStateStore, ITransactionalStateStore where T : class
17 | {
18 | }
19 |
20 | internal sealed class MockTransactionalStateStore : MockStateStore, ITransactionalStateStore where T : class
21 | {
22 | private readonly IMockTransactionalStateStore proxy;
23 |
24 | public MockTransactionalStateStore(IMockTransactionalStateStore proxy)
25 | : base(proxy)
26 | {
27 | this.proxy = proxy;
28 | }
29 |
30 | #region ITransactionalStateStore Members
31 |
32 | public Task TransactAsync(StateStoreTransactRequest request, CancellationToken cancellationToken = default)
33 | {
34 | return this.proxy.TransactAsync(request, cancellationToken);
35 | }
36 |
37 | #endregion
38 | }
39 |
--------------------------------------------------------------------------------
/src/Dapr.PluggableComponents.Tests/Components/StateStore/StateStoreGetRequestTests.cs:
--------------------------------------------------------------------------------
1 | // ------------------------------------------------------------------------
2 | // Copyright 2023 The Dapr Authors
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | // http://www.apache.org/licenses/LICENSE-2.0
7 | // Unless required by applicable law or agreed to in writing, software
8 | // distributed under the License is distributed on an "AS IS" BASIS,
9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | // See the License for the specific language governing permissions and
11 | // limitations under the License.
12 | // ------------------------------------------------------------------------
13 |
14 | using Dapr.Proto.Components.V1;
15 | using Xunit;
16 |
17 | namespace Dapr.PluggableComponents.Components.StateStore;
18 |
19 | public sealed class StateStoreGetRequestTests
20 | {
21 | [Theory]
22 | [InlineData("", "")]
23 | [InlineData("key", "key")]
24 | public void FromGetRequestKeyTests(string key, string expectedKey)
25 | {
26 | var grpcRequest = new GetRequest
27 | {
28 | Key = key
29 | };
30 |
31 | var request = StateStoreGetRequest.FromGetRequest(grpcRequest);
32 |
33 | Assert.Equal(expectedKey, request.Key);
34 | }
35 |
36 | public static IEnumerable