Compare commits

...

91 Commits

Author SHA1 Message Date
Javier Aliaga 16374cdb7b
chore: Use latest dapr/dapr version (#731)
* chore: Use latest dapr/dapr version

Signed-off-by: Javier Aliaga <javier@diagrid.io>

* chore: Bump golangci version

Signed-off-by: Javier Aliaga <javier@diagrid.io>

* chore: Bump golangci-lint version

Signed-off-by: Javier Aliaga <javier@diagrid.io>

* chore: Fix lint errors on tooling

Signed-off-by: Javier Aliaga <javier@diagrid.io>

* chore: Increase sleep to service example

Signed-off-by: Javier Aliaga <javier@diagrid.io>

---------

Signed-off-by: Javier Aliaga <javier@diagrid.io>
2025-06-03 05:59:33 -07:00
dependabot[bot] a3df75f17b
chore(deps): bump golang.org/x/net from 0.34.0 to 0.36.0 (#710)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.34.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.34.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-13 10:09:46 +08:00
Mike Nguyen 81312e9da9
merge release-1.12 into main (#703)
* Adding the name of the failing activity. For more detail (#678)

Signed-off-by: arturo <jarturotrenard@gmail.com>

* add deadlettertopic support to non-streaming subscriptions (#685)

* add deadlettertopic support to non-streaming subscriptions

Signed-off-by: yaron2 <schneider.yaron@live.com>

* fix tests

Signed-off-by: yaron2 <schneider.yaron@live.com>

---------

Signed-off-by: yaron2 <schneider.yaron@live.com>

* Pick #674 and bump to rc13 (#686)

* Bump gover, tag, x/deps and dapr (#674)

* release: bump to rc2

Signed-off-by: mikeee <hey@mike.ee>

* chore: upgrade x/net and x/crypto

Signed-off-by: mikeee <hey@mike.ee>

* release: bump go to 1.23.5 and dapr to rc5

Signed-off-by: mikeee <hey@mike.ee>

* ci: bump validation workflow versions

Signed-off-by: mikeee <hey@mike.ee>

* bump cli and runtime to latest rc

Signed-off-by: Mike Nguyen <hey@mike.ee>

* chore: bump dapr to rc7 and dt-go to head

Signed-off-by: Mike Nguyen <hey@mike.ee>

* chore: bump to rc8

Signed-off-by: mikeee <hey@mike.ee>

* chore(release): bump to latest

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
Signed-off-by: Mike Nguyen <hey@mike.ee>

* chore: bump cli and runtime vers

Signed-off-by: Mike Nguyen <hey@mike.ee>

* chore: bump to rc13

Signed-off-by: Mike Nguyen <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
Signed-off-by: Mike Nguyen <hey@mike.ee>

* feat: reconnect stream when grpc code is unknown / unavailable (#692)

* feat: reconnect stream when grpc code is unknown / unavailable

Signed-off-by: Eileen Yu <eileenylj@gmail.com>

* log error for closing stream

Signed-off-by: Eileen Yu <eileenylj@gmail.com>

---------

Signed-off-by: Eileen Yu <eileenylj@gmail.com>

* ci: include pre-release label for RCs (#675)

* ci: include pre-release label for RCs

Signed-off-by: Mike Nguyen <hey@mike.ee>

* ci: enumerate if statements

Signed-off-by: Mike Nguyen <hey@mike.ee>

---------

Signed-off-by: Mike Nguyen <hey@mike.ee>

* docs(sdk): add basic workflow example (#691)

* docs(sdk): add basic workflow example

Signed-off-by: Mike Nguyen <hey@mike.ee>

* docs: fix indentations

Signed-off-by: Mike Nguyen <hey@mike.ee>

---------

Signed-off-by: Mike Nguyen <hey@mike.ee>

* update conversation api field name (#695)

Signed-off-by: yaron2 <schneider.yaron@live.com>

* fix(examples): update deprecated flag (#689)

* fix(examples): update deprecated flag

Signed-off-by: Mike Nguyen <hey@mike.ee>

* ci: test cli PR

Signed-off-by: Mike Nguyen <hey@mike.ee>

* test(service): bump body size to 41Mi

Signed-off-by: Mike Nguyen <hey@mike.ee>

* chore: bump cli to rc6 and runtime to rc16

Signed-off-by: Mike Nguyen <hey@mike.ee>

---------

Signed-off-by: Mike Nguyen <hey@mike.ee>
Co-authored-by: Yaron Schneider <schneider.yaron@live.com>

* release: v1.12.0 version (#700)

Signed-off-by: Mike Nguyen <hey@mike.ee>

* ci: revert rc tests (#701)

Signed-off-by: Mike Nguyen <hey@mike.ee>

---------

Signed-off-by: arturo <jarturotrenard@gmail.com>
Signed-off-by: yaron2 <schneider.yaron@live.com>
Signed-off-by: mikeee <hey@mike.ee>
Signed-off-by: Mike Nguyen <hey@mike.ee>
Signed-off-by: Eileen Yu <eileenylj@gmail.com>
Co-authored-by: Arturo Trenard <jarturotrenard@gmail.com>
Co-authored-by: Yaron Schneider <schneider.yaron@live.com>
Co-authored-by: Eileen Yu <48944635+Eileen-Yu@users.noreply.github.com>
2025-02-28 12:30:46 -08:00
Mike Nguyen c81a381811
Bump gover, tag, x/deps and dapr (#674)
* release: bump to rc2

Signed-off-by: mikeee <hey@mike.ee>

* chore: upgrade x/net and x/crypto

Signed-off-by: mikeee <hey@mike.ee>

* release: bump go to 1.23.5 and dapr to rc5

Signed-off-by: mikeee <hey@mike.ee>

* ci: bump validation workflow versions

Signed-off-by: mikeee <hey@mike.ee>

* bump cli and runtime to latest rc

Signed-off-by: Mike Nguyen <hey@mike.ee>

* chore: bump dapr to rc7 and dt-go to head

Signed-off-by: Mike Nguyen <hey@mike.ee>

* chore: bump to rc8

Signed-off-by: mikeee <hey@mike.ee>

* chore(release): bump to latest

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-02-03 15:02:44 -08:00
Mike Nguyen aded0b64d7
release: version bump and tidy (#673)
Signed-off-by: mikeee <hey@mike.ee>
2025-01-15 10:50:38 -08:00
Yaron Schneider 34fd54eb81
Add trace headers to http subscriptions (#671)
* add trace headers to http subscriptions

Signed-off-by: yaron2 <schneider.yaron@live.com>

* fix json

Signed-off-by: yaron2 <schneider.yaron@live.com>

---------

Signed-off-by: yaron2 <schneider.yaron@live.com>
2025-01-13 13:12:39 -08:00
Mike Nguyen c97fd6f30d
chore: bump validation dapr runtime to 1.15.0-rc.2 (#667)
* chore: bump validation dapr runtime to 1.15.0-rc.2

Signed-off-by: Mike Nguyen <hey@mike.ee>

* fix: replace dead api

Signed-off-by: Mike Nguyen <hey@mike.ee>

* fix: remove duetime and period

The scheduler reminders subsystem now being the default

Signed-off-by: Mike Nguyen <hey@mike.ee>

---------

Signed-off-by: Mike Nguyen <hey@mike.ee>
2025-01-13 08:37:02 -08:00
Fabian Martinez 2ab3420adc
update durabletask ref (#666)
* update durabletask ref

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* lint

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

---------

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>
2025-01-03 01:30:30 -08:00
Diego Cardoso 495a389ff0
Update Dependencies - fix sec vulnerability (#658)
* update dependencies

* update dependencies
2024-12-13 08:44:16 -08:00
Hannah Hunter 7c63bb9ae1
add workflow to client doc (#657)
Signed-off-by: Hannah Hunter <hannahhunter@microsoft.com>
2024-12-09 17:06:46 -08:00
Michael Collins 31346f0d54
Introduce interface for topic event subscriber (#661)
* Introduce interface for topic event subscriber

I introduced the TopicEventSubscriber interface to allow for
subscribers to be implemented as structs. This will allow subscribers
to be initialized with any settings or dependencies needed to process
incoming events.

I converted TopicEventHandler to implement TopicEventSubscriber. I
revised TopicRegistrar to store TopicEventSubscribers instead of
TopicEventHandlers.

Resolves #660

Signed-off-by: Michael Collins <mfcollins3@me.com>

* Update go-service documentation

I added examples of how to use the TopicEventSubscriber interface to
create a new subscriber for both HTTP and gRPC services.

Signed-off-by: Michael Collins <mfcollins3@me.com>

---------

Signed-off-by: Michael Collins <mfcollins3@me.com>
2024-12-09 08:54:56 -08:00
Fabian Martinez 921a6a79c5
update durabletask to use fork and child workflow retries (#656)
* update durabletask to use fork and child workflow retries

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* lint

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

---------

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>
2024-12-04 07:12:56 -08:00
dependabot[bot] 282a58bc9c
chore(deps): bump github.com/dapr/dapr (#655)
Bumps [github.com/dapr/dapr](https://github.com/dapr/dapr) from 1.14.5-0.20241120233620-c86a77f6db5f to 1.15.0-rc.1.
- [Release notes](https://github.com/dapr/dapr/releases)
- [Changelog](https://github.com/dapr/dapr/blob/master/RELEASE.md)
- [Commits](https://github.com/dapr/dapr/commits/v1.15.0-rc.1)

---
updated-dependencies:
- dependency-name: github.com/dapr/dapr
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 12:58:38 -08:00
Mike Nguyen dce63f1917
Add support for the conversation API (#646)
* feat: conversation api implementation

Signed-off-by: mikeee <hey@mike.ee>

* chore: deps for conversation api

Signed-off-by: mikeee <hey@mike.ee>

* fix: cleanup convo example

Signed-off-by: mikeee <hey@mike.ee>

* refactor: add a conversationrequest builder and docs

Signed-off-by: mikeee <hey@mike.ee>

* fix: lint and refactor, adding preallocations for ins/outs

Signed-off-by: Mike Nguyen <hey@mike.ee>

* fix: lint and imports

Signed-off-by: mikeee <hey@mike.ee>

* fix: bump to dapr master refs

Signed-off-by: mikeee <hey@mike.ee>

* fix: enable scheduler with cli fix + tidy

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-27 07:57:22 -08:00
Mike Nguyen e52d60c714
ci: remove runtime version override (#642)
* ci: remove runtime version override

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove base64 decode for jobs api example

Signed-off-by: mikeee <hey@mike.ee>

* fix(tests): update jobs api test

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
Co-authored-by: Yaron Schneider <schneider.yaron@live.com>
2024-11-20 08:09:32 -08:00
Fabian Martinez 87659bf63e
add deprecation comments (#650)
Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>
2024-11-20 08:04:26 -08:00
Fabian Martinez c12c9594c4
worflows: activity retry policy (#644)
* worflows: activity retry policy

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* adjust name

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* fix build

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* add tests

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* register activity

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

---------

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>
Co-authored-by: Mike Nguyen <hey@mike.ee>
2024-11-13 22:02:27 -07:00
Mike Nguyen 59acca46a6
chore!: upgrade lint & go (#649)
* chore: bump go to 1.23.3 and golangci-lint to 1.61.0

Signed-off-by: mikeee <hey@mike.ee>

* fix: ineffective nolint directive removed

Signed-off-by: Mike Nguyen <hey@mike.ee>

* fix: perfsprint recommendations

Signed-off-by: Mike Nguyen <hey@mike.ee>

* fix: intrange recommendations - refactor loops

Signed-off-by: Mike Nguyen <hey@mike.ee>

* fix: remove existing dereferencing copies

Signed-off-by: Mike Nguyen <hey@mike.ee>

* fix!: address gosec overflows

BREAKING CHANGE: State consistency, concurrency and operation types are now int32 sized.
Panic on an overflow conversion for a proto duration

Signed-off-by: Mike Nguyen <hey@mike.ee>

* fix: tooling lint issues/ci update

Signed-off-by: Mike Nguyen <hey@mike.ee>

* fix: perfsprint suggestions on dapr-bot

Signed-off-by: Mike Nguyen <hey@mike.ee>

* chore(ci): remove gover remnants

Signed-off-by: Mike Nguyen <hey@mike.ee>

* chore(ci): upgrade golangci-lint action version

Signed-off-by: Mike Nguyen <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-11-13 22:01:59 -07:00
Mike Nguyen 3fff121af7
ci: only test using go.mod version (#647)
Signed-off-by: mikeee <hey@mike.ee>
2024-11-05 11:19:31 -08:00
Fabian Martinez dd9a2d5a3c
workflow examples: remove use of deprecated functions (#640)
* workflow examples: remove use of deprecated functions

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* fix example tests

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* Update README.md

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* Update Makefile

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

---------

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>
2024-10-30 09:06:32 -07:00
Fabian Martinez 516684c202
workflows: support set custom status (#639)
Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>
2024-10-30 09:06:20 -07:00
Fabian Martinez e317f06e65
add purge options (#638)
* add options to PurgeWorkflow

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* Update client.go

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

---------

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>
2024-10-30 09:06:07 -07:00
Fabian Martinez 4953b123ad
workflows support reuse id policy (#637)
* workflows support reuse id policy

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* add new type

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* lint

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* wrap all types

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* use existing type

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

---------

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>
2024-10-30 09:05:50 -07:00
Gowtham H N a074ea7428
Fixed superfluous bug (#619)
Signed-off-by: Gowtham H N <44719307+GowthamHN@users.noreply.github.com>
2024-10-28 10:51:07 -07:00
Yaron Schneider f9baae2539
Merge pull request #641 from mikeee/release-1.11
merge Release 1.11  to main
2024-10-22 20:29:11 -07:00
Yaron Schneider 6c59092f53
Change refs to 1.14.1 (#615)
* test 1.14.1-rc.1

Signed-off-by: yaron2 <schneider.yaron@live.com>

* update to 1.14.1

Signed-off-by: yaron2 <schneider.yaron@live.com>

---------

Signed-off-by: yaron2 <schneider.yaron@live.com>
2024-08-15 08:51:44 -07:00
Mike Nguyen f87f366fe7
Merge pull request #612 from mikeee/dapr1.14
chore: upgrade dapr to v1.14.0
2024-08-14 16:47:13 +01:00
mikeee 2749284a00
ci: remove version override
Signed-off-by: mikeee <hey@mike.ee>
2024-08-14 06:46:09 +01:00
mikeee 2cfb6e308e
chore: upgrade dapr to v1.14.0
Signed-off-by: mikeee <hey@mike.ee>
2024-08-14 06:36:43 +01:00
Mike Nguyen d1f04ee738
chore: bump dapr & cli to rc.8 to test (#606)
Signed-off-by: mikeee <hey@mike.ee>
2024-08-08 13:02:14 -07:00
Yaron Schneider d36c48d92e
fix version (#604)
Signed-off-by: yaron2 <schneider.yaron@live.com>
2024-07-26 12:42:32 -07:00
Josh van Leeuwen 9bc7d823cc
Update streaming subscription to understand new initial response (#601)
* Update streaming subscription to understand new initial response

Signed-off-by: joshvanl <me@joshvanl.dev>

* Update dapr CLI to 1.14.0-rc.6

Signed-off-by: joshvanl <me@joshvanl.dev>

* Update streamsub name in validate examples

Signed-off-by: joshvanl <me@joshvanl.dev>

* Apply suggestions from code review

Co-authored-by: Mike Nguyen <hey@mike.ee>
Signed-off-by: Josh van Leeuwen <me@joshvanl.dev>

---------

Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: Josh van Leeuwen <me@joshvanl.dev>
Co-authored-by: Mike Nguyen <hey@mike.ee>
2024-07-23 13:53:33 -07:00
Mike Nguyen 7c03c7ce58
chore: remove dapr stop steps and add appropriate timeouts (#573)
Signed-off-by: mikeee <hey@mike.ee>
2024-07-22 13:10:02 -07:00
Willi Eggeling 4a9f1800b6
removed unnecessary warnings from actor reflection (#586)
When checking for valid Actor methods, the SDK no longer emits warnings about invalid or inappropriate method signatures for the ones needed to be implemented for each Actor type.

Fixes #585

Signed-off-by: Willi Eggeling <thewilli@users.noreply.github.com>
2024-07-22 12:51:47 -07:00
Mike Nguyen 77c213de61
fix: stop schedule field from always being initialised (#597)
Signed-off-by: mikeee <hey@mike.ee>
2024-07-22 12:19:53 -07:00
Mike Nguyen 967570515b
Implement distributed scheduler building block (#562)
* feat: add jobs/scheduling api (with validation override)

Signed-off-by: mikeee <hey@mike.ee>

* chore: fix deps

Signed-off-by: mikeee <hey@mike.ee>

* fix: use cli fix

Signed-off-by: mikeee <hey@mike.ee>

* fix: ci artifact path set for cli build

Signed-off-by: mikeee <hey@mike.ee>

* chore: remove sidecar step

Signed-off-by: mikeee <hey@mike.ee>

* chore: revert changes to other examples

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-07-17 09:04:45 -07:00
Mike Nguyen 01c0f3154f
fix: bidipubsub example (#594)
* fix: bidipubsub example

Signed-off-by: mikeee <hey@mike.ee>

* ci: pin dapr to 1.14.0-rc.2 and cli commit that starts the scheduler

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-07-16 10:54:32 -07:00
Josh van Leeuwen b7b90e3f8e
Bidirectional Subscriptions (#578)
* Bidirectional Subscriptions

Adds support for bidirectional subscriptions to PubSubs. Adds two
methods for subscribing- one using a callback and one using an
imperative approach. Both giving support to different programming styles
or use cases.

Adds example with tests.

Signed-off-by: joshvanl <me@joshvanl.dev>

* Linting: Remove unused `closeCh`

Signed-off-by: joshvanl <me@joshvanl.dev>

* Fixes comment order in bidisub.go

Signed-off-by: joshvanl <me@joshvanl.dev>

* Add comment about processing message

Signed-off-by: joshvanl <me@joshvanl.dev>

* Adds dead letter topic example

Signed-off-by: joshvanl <me@joshvanl.dev>

* chore: remove go.mod

Signed-off-by: mikeee <hey@mike.ee>

* Updates go mod to v1.14.0-rc.1

Signed-off-by: joshvanl <me@joshvanl.dev>

---------

Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: mikeee <hey@mike.ee>
Signed-off-by: Mike Nguyen <hey@mike.ee>
Co-authored-by: mikeee <hey@mike.ee>
2024-07-11 07:43:51 -07:00
Fabian Martinez a1e723bd29
make workflow client struct public (#577)
Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>
2024-07-10 09:26:12 +08:00
dependabot[bot] d3eef2eb18
Bump github.com/go-chi/chi/v5 from 5.0.12 to 5.1.0 (#587)
Bumps [github.com/go-chi/chi/v5](https://github.com/go-chi/chi) from 5.0.12 to 5.1.0.
- [Release notes](https://github.com/go-chi/chi/releases)
- [Changelog](https://github.com/go-chi/chi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-chi/chi/compare/v5.0.12...v5.1.0)

---
updated-dependencies:
- dependency-name: github.com/go-chi/chi/v5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 09:25:21 +08:00
dependabot[bot] 34129df6fb
Bump google.golang.org/grpc from 1.64.0 to 1.65.0 (#590)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.64.0 to 1.65.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.64.0...v1.65.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 09:25:02 +08:00
Sam feb4bb675c
fix(security): bump security vulnerabilities (#582)
* fix(security): bump security vulnerabilities

Signed-off-by: Samantha Coyle <sam@diagrid.io>

* style: make linter happy

Signed-off-by: Samantha Coyle <sam@diagrid.io>

---------

Signed-off-by: Samantha Coyle <sam@diagrid.io>
Signed-off-by: Mike Nguyen <hey@mike.ee>
Co-authored-by: Mike Nguyen <hey@mike.ee>
2024-07-01 17:27:27 -07:00
Mike Nguyen 2e8248517f
chore: cleanup repo (#571)
* chore: cleanup examples

Signed-off-by: mikeee <hey@mike.ee>

* chore: bump dapr and durabletask-go deps

Signed-off-by: mikeee <hey@mike.ee>

* ci: bump golangci and fossa actions versions

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
Signed-off-by: Mike Nguyen <hey@mike.ee>
2024-07-01 09:58:37 -07:00
Fabian Martinez c417f950fe
Prevent workflows client nilpointer (#583)
* bump durabletask dep

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* workflows client, prevent nilpointer error on convertMetadata

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

---------

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>
2024-06-26 06:55:42 -07:00
Anton Troshin dd35c21392
Added a check for existing healthz route to avoid overwriting user custom handler (#580)
Signed-off-by: Anton Troshin <anton@diagrid.io>
2024-06-20 12:57:39 -07:00
manojks1999 33180dd89a
Dependabot added in workflow. (#531)
* daily_workflow_added

Signed-off-by: manojks1999 <9743manoj@gmail.com>

* removed_newline

Signed-off-by: manojks1999 <9743manoj@gmail.com>

---------

Signed-off-by: manojks1999 <9743manoj@gmail.com>
2024-05-07 09:04:35 -07:00
Mike Nguyen 0c60bbd3a4
fix: add crypto validation example and fix mechanical markdown (#544)
* fix: add crypto validation example and fix mechanical markdown

Signed-off-by: mikeee <hey@mike.ee>

* fix: update test assertion and remove cleanup step

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-05-06 15:35:18 +08:00
Yaron Schneider b2ead493ac
Merge pull request #556 from dapr/dependabot/go_modules/golang.org/x/net-0.23.0
Bump golang.org/x/net from 0.21.0 to 0.23.0
2024-04-20 10:46:08 -07:00
dependabot[bot] 1496a415fa
Bump golang.org/x/net from 0.21.0 to 0.23.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.21.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.21.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-19 13:07:09 +00:00
Rutam Prita Mishra b0ea7596ac
Update holopin.yml to award SDK badge to contributors (#547)
# Description

The `yaml` file to award SDK badges had been updated such that each contributor can be awarded with a SDK badge for their contribution to this repo.

## Issue reference

This PR fixes #546 

### Please reference the issue this PR will close: #546 

## Checklist

Please make sure you've  completed the relevant tasks for this PR, out of the following list:

* [x] Code compiles correctly.
* [x] Correct and accurate change has been done as per the issue suggestion.
* [x] YAML doesn't throw any error.

Signed-off-by: Rutam Prita Mishra <rutamprita@gmail.com>
2024-04-15 16:04:57 +08:00
Yaron Schneider 8c7cc2d68b
Merge pull request #529 from mikeee/update-release1.10
Bring release1.10 into main
2024-03-06 07:04:21 -08:00
mikeee 37ff65ccc0
Merge branch 'main' into update-release1.10
Signed-off-by: mikeee <hey@mike.ee>
2024-03-06 14:52:33 +00:00
Yaron Schneider c193b83e10
[1.13] update dapr/dapr dep (#528)
Signed-off-by: yaron2 <schneider.yaron@live.com>
2024-03-06 14:46:38 +00:00
Mike Nguyen 50ffb8861b
chore: bump go to 1.21.8 and protobuf library to 1.33.0 (#524)
* chore: bump go to 1.21.8 and protobuf library to 1.33.0

Signed-off-by: mikeee <hey@mike.ee>

* fix: cleanup 🧹 (go mod tidy)

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-03-06 14:46:11 +00:00
dependabot[bot] 9642b712e2
Bump github.com/dapr/dapr from 1.13.0-rc.7 to 1.13.0-rc.8 (#519)
Bumps [github.com/dapr/dapr](https://github.com/dapr/dapr) from 1.13.0-rc.7 to 1.13.0-rc.8.
- [Release notes](https://github.com/dapr/dapr/releases)
- [Commits](https://github.com/dapr/dapr/compare/v1.13.0-rc.7...v1.13.0-rc.8)

---
updated-dependencies:
- dependency-name: github.com/dapr/dapr
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: mikeee <hey@mike.ee>
2024-03-06 14:46:09 +00:00
Yaron Schneider aaf21f29cd
update sdk-version (#517)
Signed-off-by: yaron2 <schneider.yaron@live.com>
Signed-off-by: mikeee <hey@mike.ee>
2024-03-06 14:46:07 +00:00
Mike Nguyen ff491f70ed
chore: bump go to 1.21.8 and protobuf library to 1.33.0 (#524)
* chore: bump go to 1.21.8 and protobuf library to 1.33.0

Signed-off-by: mikeee <hey@mike.ee>

* fix: cleanup 🧹 (go mod tidy)

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-03-05 12:58:46 -08:00
dependabot[bot] 5ef7aa2234
Bump github.com/dapr/dapr from 1.13.0-rc.7 to 1.13.0-rc.8 (#519)
Bumps [github.com/dapr/dapr](https://github.com/dapr/dapr) from 1.13.0-rc.7 to 1.13.0-rc.8.
- [Release notes](https://github.com/dapr/dapr/releases)
- [Commits](https://github.com/dapr/dapr/compare/v1.13.0-rc.7...v1.13.0-rc.8)

---
updated-dependencies:
- dependency-name: github.com/dapr/dapr
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-28 17:20:40 -08:00
Yaron Schneider 3bfc94e8a8
update sdk-version (#517)
Signed-off-by: yaron2 <schneider.yaron@live.com>
2024-02-27 08:58:57 -08:00
dependabot[bot] 5ec8e7f3ac
Bump google.golang.org/grpc from 1.61.1 to 1.62.0 (#515)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.61.1 to 1.62.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.61.1...v1.62.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-22 14:03:06 -08:00
dependabot[bot] b6d9960c8e
Bump github.com/dapr/dapr from 1.13.0-rc.6 to 1.13.0-rc.7 (#514)
Bumps [github.com/dapr/dapr](https://github.com/dapr/dapr) from 1.13.0-rc.6 to 1.13.0-rc.7.
- [Release notes](https://github.com/dapr/dapr/releases)
- [Commits](https://github.com/dapr/dapr/compare/v1.13.0-rc.6...v1.13.0-rc.7)

---
updated-dependencies:
- dependency-name: github.com/dapr/dapr
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-22 14:02:40 -08:00
dependabot[bot] 7e5ee73aa8
Bump github.com/go-chi/chi/v5 from 5.0.11 to 5.0.12 (#512)
Bumps [github.com/go-chi/chi/v5](https://github.com/go-chi/chi) from 5.0.11 to 5.0.12.
- [Release notes](https://github.com/go-chi/chi/releases)
- [Changelog](https://github.com/go-chi/chi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-chi/chi/compare/v5.0.11...v5.0.12)

---
updated-dependencies:
- dependency-name: github.com/go-chi/chi/v5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-20 09:25:07 +08:00
dependabot[bot] eaaaf9c27d
Bump github.com/dapr/dapr from 1.13.0-rc.2 to 1.13.0-rc.6 (#511)
Bumps [github.com/dapr/dapr](https://github.com/dapr/dapr) from 1.13.0-rc.2 to 1.13.0-rc.6.
- [Release notes](https://github.com/dapr/dapr/releases)
- [Commits](https://github.com/dapr/dapr/compare/v1.13.0-rc.2...v1.13.0-rc.6)

---
updated-dependencies:
- dependency-name: github.com/dapr/dapr
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-19 07:58:46 -08:00
dependabot[bot] 4d5c9103a3
Bump google.golang.org/grpc from 1.61.0 to 1.61.1 (#505)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.61.0 to 1.61.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.61.0...v1.61.1)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-16 13:16:01 -08:00
mikeee 3fe2ed0e46
add support for parallel workflows (#509)
Signed-off-by: mikeee <hey@mike.ee>
2024-02-15 07:12:04 -08:00
mikeee 60e472293e
docs: fix authentication header level (#506)
Signed-off-by: mikeee <hey@mike.ee>
2024-02-14 08:48:29 -08:00
Gustavo Chaín 1a347b201c
allow to customize the default logger (#496)
Signed-off-by: Gustavo Chain <me@qustavo.cc>
2024-02-13 10:48:48 -08:00
mikeee ac26e622c4
feat: workflow authoring and management support (#487)
* feat: initial workflow

Signed-off-by: mikeee <hey@mike.ee>

* test: add activity context test for input

Signed-off-by: mikeee <hey@mike.ee>

* test: add context texts

Signed-off-by: mikeee <hey@mike.ee>

* fix/test: identify anonymous functions and add tests to runtime

Signed-off-by: mikeee <hey@mike.ee>

* chore: lint and minor fixes

Signed-off-by: mikeee <hey@mike.ee>

* chore: improve readability+tests and implement context method

Signed-off-by: mikeee <hey@mike.ee>

* test: add nil coverage

Signed-off-by: mikeee <hey@mike.ee>

* feat: workflow implementation wip

Signed-off-by: mikeee <hey@mike.ee>

* chore: add missing actor, configuration and workflow runners for validation

Signed-off-by: mikeee <hey@mike.ee>

* chore: lint

Signed-off-by: mikeee <hey@mike.ee>

* fix: missing formatting directives

Signed-off-by: mikeee <hey@mike.ee>

* feat: implement wf state

Signed-off-by: mikeee <hey@mike.ee>

* feat: add workflow management

Signed-off-by: mikeee <hey@mike.ee>

* chore: fix direct proto field references and general lint

Signed-off-by: mikeee <hey@mike.ee>

* fix: correct states

Signed-off-by: mikeee <hey@mike.ee>

* fix: refactor workflow contexts

Signed-off-by: mikeee <hey@mike.ee>

* fix: increase verbosity and move channel

Signed-off-by: mikeee <hey@mike.ee>

* fix: implement full workflow validation

Signed-off-by: mikeee <hey@mike.ee>

* fix: add dapr-app-id to example

Signed-off-by: mikeee <hey@mike.ee>

* fix: set endpoint

Signed-off-by: mikeee <hey@mike.ee>

* chore: revert actor mod change

Signed-off-by: mikeee <hey@mike.ee>

* chore: revert sum addition

Signed-off-by: mikeee <hey@mike.ee>

* fix: wrap wf management set authtoken in context

Signed-off-by: mikeee <hey@mike.ee>

* fix: migrate to dapr builtin sdk client

Signed-off-by: mikeee <hey@mike.ee>

* fix: correct runtime testing logic and lint
The runtime creation should never be successful in test

Signed-off-by: mikeee <hey@mike.ee>

* fix: implement delayed cancellation

Signed-off-by: mikeee <hey@mike.ee>

* fix(minor): rename getDecorator to getFunctionName

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove alpha workflow

Signed-off-by: mikeee <hey@mike.ee>

* fix(validation): remove redundant result line

Signed-off-by: mikeee <hey@mike.ee>

* feat: initial wfclient implementation

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove redundant closer and fix comparison

Signed-off-by: mikeee <hey@mike.ee>

* tests: improve unit test coverage

Signed-off-by: mikeee <hey@mike.ee>

* fix: cleanup

Signed-off-by: mikeee <hey@mike.ee>

* fix: wording change

Co-authored-by: Chris Gillum <cgillum@gmail.com>
Signed-off-by: mikeee <hey@mike.ee>

* fix: wording change

Co-authored-by: Chris Gillum <cgillum@gmail.com>
Signed-off-by: mikeee <hey@mike.ee>

* chore: bump durabletask-go and deps

Signed-off-by: mikeee <hey@mike.ee>

* chore: add copyright

Signed-off-by: mikeee <hey@mike.ee>

* fix: refactor from runtime to worker and other minor changes

Signed-off-by: mikeee <hey@mike.ee>

* fix: update worker tests

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove workflow component requirement and return worker error

Signed-off-by: mikeee <hey@mike.ee>

* fix: reason field validation removed

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove reason tests

Signed-off-by: mikeee <hey@mike.ee>

* refactoring

Signed-off-by: mikeee <hey@mike.ee>

* fix: inputs

Signed-off-by: mikeee <hey@mike.ee>

* tests: add coverage to activity options

Signed-off-by: mikeee <hey@mike.ee>

* feat: add worker options

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove unused logger

Signed-off-by: mikeee <hey@mike.ee>

* feat: add client options and testing

Signed-off-by: mikeee <hey@mike.ee>

* feat: decouple metadata

Signed-off-by: mikeee <hey@mike.ee>

* chore: remove unused client interface

Signed-off-by: mikeee <hey@mike.ee>

* chore: update tests

Signed-off-by: mikeee <hey@mike.ee>

* chore: lint

Signed-off-by: mikeee <hey@mike.ee>

* test: improve coverage

Signed-off-by: mikeee <hey@mike.ee>

* tests: improve unit coverage

Signed-off-by: mikeee <hey@mike.ee>

* feat: initial workflow

Signed-off-by: mikeee <hey@mike.ee>

* test: add activity context test for input

Signed-off-by: mikeee <hey@mike.ee>

* test: add context texts

Signed-off-by: mikeee <hey@mike.ee>

* fix/test: identify anonymous functions and add tests to runtime

Signed-off-by: mikeee <hey@mike.ee>

* chore: lint and minor fixes

Signed-off-by: mikeee <hey@mike.ee>

* chore: improve readability+tests and implement context method

Signed-off-by: mikeee <hey@mike.ee>

* test: add nil coverage

Signed-off-by: mikeee <hey@mike.ee>

* feat: workflow implementation wip

Signed-off-by: mikeee <hey@mike.ee>

* chore: add missing actor, configuration and workflow runners for validation

Signed-off-by: mikeee <hey@mike.ee>

* chore: lint

Signed-off-by: mikeee <hey@mike.ee>

* fix: missing formatting directives

Signed-off-by: mikeee <hey@mike.ee>

* feat: implement wf state

Signed-off-by: mikeee <hey@mike.ee>

* feat: add workflow management

Signed-off-by: mikeee <hey@mike.ee>

* chore: fix direct proto field references and general lint

Signed-off-by: mikeee <hey@mike.ee>

* fix: correct states

Signed-off-by: mikeee <hey@mike.ee>

* fix: refactor workflow contexts

Signed-off-by: mikeee <hey@mike.ee>

* fix: increase verbosity and move channel

Signed-off-by: mikeee <hey@mike.ee>

* fix: implement full workflow validation

Signed-off-by: mikeee <hey@mike.ee>

* fix: add dapr-app-id to example

Signed-off-by: mikeee <hey@mike.ee>

* fix: set endpoint

Signed-off-by: mikeee <hey@mike.ee>

* chore: revert actor mod change

Signed-off-by: mikeee <hey@mike.ee>

* chore: revert sum addition

Signed-off-by: mikeee <hey@mike.ee>

* fix: wrap wf management set authtoken in context

Signed-off-by: mikeee <hey@mike.ee>

* fix: migrate to dapr builtin sdk client

Signed-off-by: mikeee <hey@mike.ee>

* fix: correct runtime testing logic and lint
The runtime creation should never be successful in test

Signed-off-by: mikeee <hey@mike.ee>

* fix: implement delayed cancellation

Signed-off-by: mikeee <hey@mike.ee>

* fix(minor): rename getDecorator to getFunctionName

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove alpha workflow

Signed-off-by: mikeee <hey@mike.ee>

* fix(validation): remove redundant result line

Signed-off-by: mikeee <hey@mike.ee>

* feat: initial wfclient implementation

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove redundant closer and fix comparison

Signed-off-by: mikeee <hey@mike.ee>

* tests: improve unit test coverage

Signed-off-by: mikeee <hey@mike.ee>

* fix: cleanup

Signed-off-by: mikeee <hey@mike.ee>

* fix: wording change

Co-authored-by: Chris Gillum <cgillum@gmail.com>
Signed-off-by: mikeee <hey@mike.ee>

* fix: wording change

Co-authored-by: Chris Gillum <cgillum@gmail.com>
Signed-off-by: mikeee <hey@mike.ee>

* chore: bump durabletask-go and deps

Signed-off-by: mikeee <hey@mike.ee>

* chore: add copyright

Signed-off-by: mikeee <hey@mike.ee>

* fix: refactor from runtime to worker and other minor changes

Signed-off-by: mikeee <hey@mike.ee>

* fix: update worker tests

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove workflow component requirement and return worker error

Signed-off-by: mikeee <hey@mike.ee>

* fix: reason field validation removed

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove reason tests

Signed-off-by: mikeee <hey@mike.ee>

* refactoring

Signed-off-by: mikeee <hey@mike.ee>

* fix: inputs

Signed-off-by: mikeee <hey@mike.ee>

* tests: add coverage to activity options

Signed-off-by: mikeee <hey@mike.ee>

* feat: add worker options

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove unused logger

Signed-off-by: mikeee <hey@mike.ee>

* feat: add client options and testing

Signed-off-by: mikeee <hey@mike.ee>

* feat: decouple metadata

Signed-off-by: mikeee <hey@mike.ee>

* chore: remove unused client interface

Signed-off-by: mikeee <hey@mike.ee>

* chore: update tests

Signed-off-by: mikeee <hey@mike.ee>

* chore: lint

Signed-off-by: mikeee <hey@mike.ee>

* test: improve coverage

Signed-off-by: mikeee <hey@mike.ee>

* tests: improve unit coverage

Signed-off-by: mikeee <hey@mike.ee>

* fix: implement code review suggestions/refactor and gracefully handle errors

Signed-off-by: mikeee <hey@mike.ee>

* fix: innerfailure handling

Signed-off-by: mikeee <hey@mike.ee>

* docs: add docs to public methods and functions

Signed-off-by: mikeee <hey@mike.ee>

* implements correction

Co-authored-by: Chris Gillum <cgillum@gmail.com>
Signed-off-by: mikeee <hey@mike.ee>

* change typecast assertion

Signed-off-by: mikeee <hey@mike.ee>

* improve clarity of notes

Signed-off-by: mikeee <hey@mike.ee>

* fix mod issues from rebasing interactively on github

Signed-off-by: mikeee <hey@mike.ee>

* implement suggestions from review

- task invoke documentation
- refactor type assertion for startworkflowbeta1

Signed-off-by: mikeee <hey@mike.ee>

* remoove unused definition

Signed-off-by: mikeee <hey@mike.ee>

* fix mod

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
Co-authored-by: Chris Gillum <cgillum@gmail.com>
2024-02-09 07:32:36 -08:00
mikeee e45054d1f6
introduces go1.22 to tests (and misc cleanup) (#504)
* introduces go1.22

- dapr-bot updated to use go1.22
- adds go1.22 to the test jobs
- adds go1.22 to tooling tests

Signed-off-by: mikeee <hey@mike.ee>

* remove 1.20 tests

Signed-off-by: mikeee <hey@mike.ee>

* dapr-bot workflow changes

- retrieve go version from go.mod
- run go mod tidy rather than go get

Signed-off-by: mikeee <hey@mike.ee>

* bump action versions and release go version is now from go.mod

Signed-off-by: mikeee <hey@mike.ee>

* bump main and tool mod files to 1.21

Signed-off-by: mikeee <hey@mike.ee>

* fix dapr-bot test

Signed-off-by: mikeee <hey@mike.ee>

* test dapr-bot using go version from go.mod

Signed-off-by: mikeee <hey@mike.ee>

* bump action versions and remove explicit caching

Signed-off-by: mikeee <hey@mike.ee>

* bump examples to go1.21 and bump deps

Signed-off-by: mikeee <hey@mike.ee>

* bump compatibility check to 1.21 in the make flow

Signed-off-by: mikeee <hey@mike.ee>

* bump to dapr1.13rc2

Signed-off-by: mikeee <hey@mike.ee>

* tidy sums

Signed-off-by: mikeee <hey@mike.ee>

* empty commit to trigger tests (flaky example service validation)

Signed-off-by: mikeee <hey@mike.ee>

* remove conditionals for modtidy/checkdiff runs

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-02-08 10:08:28 -08:00
Josh van Leeuwen cefbadb3d1
Update github.com/dapr/dapr to v1.13.0-rc.1 (#503)
* Update github.com/dapr/dapr to v1.13.0-rc.1

Signed-off-by: joshvanl <me@joshvanl.dev>

* Revert go.mod to use Go 1.20 as minimum version

Signed-off-by: joshvanl <me@joshvanl.dev>

* github actions: only perform go mod diff on same go version

Signed-off-by: joshvanl <me@joshvanl.dev>

---------

Signed-off-by: joshvanl <me@joshvanl.dev>
2024-02-07 07:54:01 -08:00
Fabian Martinez 4585a36efd
refactor setting of api token (#502)
* refactor setting of api token

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* fix breaking change

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* fix test build

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

* typo

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>

---------

Signed-off-by: Fabian Martinez <46371672+famarting@users.noreply.github.com>
2024-01-29 17:24:12 -08:00
mikeee a65eddaa4e
fix: Overhaul the validation action (#495)
* fix: remove the referenced daprd tag

Signed-off-by: mikeee <hey@mike.ee>

* update example validation flow

Signed-off-by: mikeee <hey@mike.ee>

* split into two+ jobs

Signed-off-by: mikeee <hey@mike.ee>

* chore: tidy

Signed-off-by: mikeee <hey@mike.ee>

* implement artifacts transfer and setup validate-example jobs

Signed-off-by: mikeee <hey@mike.ee>

* fix: only run the artifact steps when generated

Signed-off-by: mikeee <hey@mike.ee>

* fix: tag outputs with a step id

Signed-off-by: mikeee <hey@mike.ee>

* fix: typo in matrix

Signed-off-by: mikeee <hey@mike.ee>

* chore: cleanup

Signed-off-by: mikeee <hey@mike.ee>

* disable fail-fast

Signed-off-by: mikeee <hey@mike.ee>

* fix: grpc-service example sleeps

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-01-19 09:07:59 -08:00
syedsadath-17 d655a2c770
Examples: Added Crypto (#492)
* Examples: Added Crypto

Signed-off-by: sadath-12 <sadathsadu2002@gmail.com>

* docs: update

Signed-off-by: sadath-12 <sadathsadu2002@gmail.com>

---------

Signed-off-by: sadath-12 <sadathsadu2002@gmail.com>
2024-01-19 08:54:36 -08:00
mikeee abe2f81af3
fix: update StateConsistency type to match protobufs (#481)
* fix: correct state consistency types

Signed-off-by: mikeee <hey@mike.ee>

* fix: add tests to type conversions

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2024-01-19 08:52:10 -08:00
Elena Kolevska 1ad973a458
Docs for error handling (#482)
* Updates docs with error handling example

Signed-off-by: Elena Kolevska <elena@kolevska.com>

* Adds docs for handling handling error details

Signed-off-by: Elena Kolevska <elena@kolevska.com>

* Updates main readme with example for handling error details

Signed-off-by: Elena Kolevska <elena@kolevska.com>

---------

Signed-off-by: Elena Kolevska <elena@kolevska.com>
2024-01-19 08:51:08 -08:00
Joni Collinge c8f3533787
Add PubSub event metadata (#490)
* Map event metadata

Signed-off-by: Joni Collinge <jonathancollinge@live.com>

* Feedback

Signed-off-by: Joni Collinge <jonathancollinge@live.com>

* Lint

Signed-off-by: Joni Collinge <jonathancollinge@live.com>

---------

Signed-off-by: Joni Collinge <jonathancollinge@live.com>
2024-01-08 10:36:39 +08:00
syedsadath-17 61158e80ea
PR template added (#484)
* PR template added

Signed-off-by: sadath-12 <sadathsadu2002@gmail.com>

* hided details

Signed-off-by: sadath-12 <sadathsadu2002@gmail.com>

* comment down

Signed-off-by: sadath-12 <sadathsadu2002@gmail.com>

---------

Signed-off-by: sadath-12 <sadathsadu2002@gmail.com>
2023-12-28 12:51:51 +08:00
syedsadath-17 d5ffe7750a
perf: enhanced configuration example (#483)
* perf: enhanced configuration example

Signed-off-by: sadath-12 <sadathsadu2002@gmail.com>

* remove "with"

Signed-off-by: sadath-12 <sadathsadu2002@gmail.com>

* update markdown

Signed-off-by: sadath-12 <sadathsadu2002@gmail.com>

* minor fix

Signed-off-by: sadath-12 <sadathsadu2002@gmail.com>

---------

Signed-off-by: sadath-12 <sadathsadu2002@gmail.com>
2023-12-28 10:19:04 +08:00
mikeee 04f7b595b6
feat: go1.20 and golangci-lint v1.55.2 (#480)
* fix: remove invalid 'unused' config and fix wsl trailing whitespace key name

Signed-off-by: mikeee <hey@mike.ee>

* fix: disable inamedparam linter

Signed-off-by: mikeee <hey@mike.ee>

* fix: update package and tool to go1.21.5

Signed-off-by: mikeee <hey@mike.ee>

* fix: correct majority of the testifylinter issues relating to error assertions

Signed-off-by: mikeee <hey@mike.ee>

* fix: reverse actual and expected values

Signed-off-by: mikeee <hey@mike.ee>

* fix: correct test cases

Signed-off-by: mikeee <hey@mike.ee>

* fix: correct misspell - upsert

Signed-off-by: mikeee <hey@mike.ee>

* fix: add missing import

Signed-off-by: mikeee <hey@mike.ee>

* update: bump validation workflow to 1.21

Signed-off-by: mikeee <hey@mike.ee>

* fix: refactor direct access references to proto fields

Signed-off-by: mikeee <hey@mike.ee>

* fix: revert to go1.20 retaining version-1 support

Signed-off-by: mikeee <hey@mike.ee>

* fix: update test-dapr-bot workflow golangci-lint ver to 1.55.2

Signed-off-by: mikeee <hey@mike.ee>

* fix: fix assertions for dapr-bot and check-lint-version

Signed-off-by: mikeee <hey@mike.ee>

* fix: remove length function call

Signed-off-by: mikeee <hey@mike.ee>

* fix: fix StateConsistency logic and add tests to satisfy codecov

Signed-off-by: mikeee <hey@mike.ee>

* tests: add coverage of empty store names for delete bulk state item method

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2023-12-11 10:51:26 +08:00
mikeee 959de75422
fix(minor): remove unsupported schemes (#479)
Signed-off-by: mikeee <hey@mike.ee>
2023-12-02 09:11:49 -08:00
Josh van Leeuwen 224a159b98
Adds `DAPR_GRPC_ENPOINT` support to client (#475)
* Adds `DAPR_GRPC_ENPOINT` support to client

PR adds `DAPR_GRPC_ENPOINT` environment variable support to client.

Address parser respects http[s] schemes, and TLS query options, as per
[0008-S-sidecar-endpoint-tls.md](https://github.com/dapr/proposals/blob/main/0008-S-sidecar-endpoint-tls.md).

`DAPR_GRPC_ENDPONT` takes precedence over `DAPR_GRPC_PORT`.

Signed-off-by: joshvanl <me@joshvanl.dev>

* Remove errors.Join to have compatibility with Go 1.19

Signed-off-by: joshvanl <me@joshvanl.dev>

---------

Signed-off-by: joshvanl <me@joshvanl.dev>
2023-12-01 10:19:56 -08:00
Cassie Coyle ae8becfcd3
add note on unsubscribeConfiguration being deprecated (#457)
* add note on unsubscribeConfiguration being deprecated

Signed-off-by: Cassandra Coyle <cassie@diagrid.io>

* Update client/client.go

Co-authored-by: Josh van Leeuwen <me@joshvanl.dev>
Signed-off-by: Cassie Coyle <cassie.i.coyle@gmail.com>

---------

Signed-off-by: Cassandra Coyle <cassie@diagrid.io>
Signed-off-by: Cassie Coyle <cassie.i.coyle@gmail.com>
Co-authored-by: Josh van Leeuwen <me@joshvanl.dev>
2023-11-06 09:54:47 +08:00
Mike a0e6f2ee22
add go 1.21 to workflow test (#440)
Signed-off-by: mikeee <hey@mike.ee>
2023-11-02 08:03:57 -07:00
Alessandro (Ale) Segala 87bbb8cd69
Updates pinned runtime (#469)
This is needed in components-contrib as we cannot pin an updated runtime in cert tests without an updated Go SDK, due to a complex circular dependency

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>
2023-11-01 20:11:49 -07:00
Mike 57466dd68e
feat: add golangci-lint (local) version check (#467)
* feat: add golangci-lint version check

Add golangci-lint version check to compare the
local version against the workflow version.

Adds associated test workflow for mac, ubuntu and windows.

Signed-off-by: mikeee <hey@mike.ee>

* fix: add install linter step

Signed-off-by: mikeee <hey@mike.ee>

* fix: return the raw output of the command run

Signed-off-by: mikeee <hey@mike.ee>

* fix: change regex to pick up versions not prefixed

Signed-off-by: mikeee <hey@mike.ee>

* formatting: gofumpt'ed workspace

Signed-off-by: mikeee <hey@mike.ee>

* fix: convert line endings to LF on checkout

Signed-off-by: mikeee <hey@mike.ee>

* fix: encapsulate any spaces in the argument

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2023-10-20 14:15:47 -07:00
Mike 30a51be967
fix: fix broken dapr setup links (#468)
Replace the dapr getting-started link with two steps to install the cli
and initialise dapr locally.

Signed-off-by: mikeee <hey@mike.ee>
2023-10-19 06:36:22 -07:00
Marc Duiker de9747742c
Add holopin.yml config (#453)
Signed-off-by: Marc Duiker <marcduiker@users.noreply.github.com>
2023-10-17 12:58:30 +08:00
Alessandro (Ale) Segala 69e788045d
Remove deprecated method RenameActorReminder (#466)
Fixes #465

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>
2023-10-13 20:26:04 -07:00
Cassie Coyle 8c41838702
go mod tidy (#463)
Signed-off-by: Cassandra Coyle <cassie@diagrid.io>
2023-10-13 16:29:23 +08:00
Mike 1757eaa082
Implement issue assign bot (#460)
* implement assign bot in go and trigger workflow

Signed-off-by: mikeee <hey@mike.ee>

* remove debug line

Signed-off-by: mikeee <hey@mike.ee>

* prevent an issue from being assigned twice

Signed-off-by: mikeee <hey@mike.ee>

* add event json annotations

Signed-off-by: mikeee <hey@mike.ee>

* add makefile and test workflow

Signed-off-by: mikeee <hey@mike.ee>

* rename workflow and job

Signed-off-by: mikeee <hey@mike.ee>

* handle multiline comments

Signed-off-by: mikeee <hey@mike.ee>

---------

Signed-off-by: mikeee <hey@mike.ee>
2023-10-10 08:09:50 -07:00
Sam c73a542ad0
fix: go mod tidy (#462)
Signed-off-by: Samantha Coyle <sam@diagrid.io>
2023-10-10 08:08:20 -07:00
160 changed files with 7792 additions and 1621 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.go text eol=lf

View File

@ -4,3 +4,7 @@ updates:
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "gomod"
directory: "/.github/workflows/dapr-bot"
schedule:
interval: "daily"

6
.github/holopin.yml vendored Normal file
View File

@ -0,0 +1,6 @@
organization: dapr
defaultSticker: clrqfdv4x24910fl5n4iwu5oa
stickers:
-
id: clrqfdv4x24910fl5n4iwu5oa
alias: sdk-badge

21
.github/pull_request_template.md vendored Normal file
View File

@ -0,0 +1,21 @@
# Description
<!--
Please explain the changes you've made.
-->
## Issue reference
<!--
We strive to have all PR being opened based on an issue, where the problem or feature have been discussed prior to implementation.
-->
Please reference the issue this PR will close: #_[issue number]_
## Checklist
Please make sure you've completed the relevant tasks for this PR, out of the following list:
* [ ] Code compiles correctly
* [ ] Created/updated tests
* [ ] Extended the documentation

34
.github/workflows/dapr-bot.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: dapr-bot
on:
issue_comment:
types: [created]
jobs:
bot-run:
name: bot-processor
runs-on: ubuntu-latest
permissions:
issues: write
contents: read
env:
GITHUB_TOKEN: ${{ github.token }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v4
with:
go-version-file: "./.github/workflows/dapr-bot/go.mod"
cache-dependency-path: |
./.github/workflows/dapr-bot/
- name: go-bot-mod
working-directory: ./.github/workflows/dapr-bot/
run: go mod tidy
- name: go-bot-run
working-directory: ./.github/workflows/dapr-bot/
run: go run .

17
.github/workflows/dapr-bot/Makefile vendored Normal file
View File

@ -0,0 +1,17 @@
GO_COMPAT_VERSION=1.22
.PHONY: cover
cover:
go test -coverprofile=cover.out ./ && go tool cover -html=cover.out
.PHONY: tidy
tidy: ## Updates the go modules
go mod tidy -compat=$(GO_COMPAT_VERSION)
.PHONY: test
test:
go test -count=1 \
-race \
-coverprofile=coverage.txt \
-covermode=atomic \
./...

95
.github/workflows/dapr-bot/bot.go vendored Normal file
View File

@ -0,0 +1,95 @@
package main
import (
"context"
"errors"
"fmt"
"net/http"
"strings"
"github.com/google/go-github/v55/github"
)
var (
errCommentBodyEmpty = errors.New("comment body is empty")
errIssueClosed = errors.New("issue is closed")
errIssueAlreadyAssigned = errors.New("issue is already assigned")
errUnauthorizedClient = errors.New("possibly unauthorized client issue")
)
type issueInterface interface {
CreateComment(ctx context.Context, owner string, repo string, number int, comment *github.IssueComment) (*github.IssueComment, *github.Response, error)
AddAssignees(ctx context.Context, owner string, repo string, number int, assignees []string) (*github.Issue, *github.Response, error)
}
type Bot struct {
ctx context.Context
issueClient issueInterface
}
func NewBot(ghClient *github.Client) *Bot {
return &Bot{
ctx: context.Background(),
issueClient: ghClient.Issues,
}
}
func (b *Bot) HandleEvent(ctx context.Context, event Event) (res string, err error) {
commentBody := event.IssueCommentEvent.Comment.GetBody()
// split the comment after any potential new lines
newline := strings.Split(strings.ReplaceAll(commentBody, "\r\n", "\n"), "\n")[0]
command := strings.Split(newline, " ")[0]
if command[0] != '/' {
return "no command found", err
}
switch command {
case "/assign":
assignee, err := b.AssignIssueToCommenter(event)
res = "👍 Issue assigned to " + assignee
if err == nil {
err = b.CreateIssueComment("🚀 Issue assigned to you @"+assignee, event)
} else {
err = b.CreateIssueComment("⚠️ Unable to assign issue", event)
}
if err != nil {
return fmt.Sprintf("failed to comment on issue: %v", err), err
}
}
return
}
func (b *Bot) CreateIssueComment(body string, event Event) error {
if body == "" {
return errCommentBodyEmpty
}
ctx := context.Background()
comment := &github.IssueComment{
Body: github.String(body),
}
_, response, err := b.issueClient.CreateComment(ctx, event.GetIssueOrg(), event.GetIssueRepo(), event.GetIssueNumber(), comment)
if err != nil || response.StatusCode == http.StatusNotFound {
return fmt.Errorf("failed to create comment: %v%v", err, response.StatusCode)
}
return nil
}
func (b *Bot) AssignIssueToCommenter(event Event) (string, error) {
if event.GetIssueState() == "closed" {
return "", errIssueClosed
}
if len(event.GetIssueAssignees()) > 0 {
return "", errIssueAlreadyAssigned
}
ctx := context.Background()
_, response, err := b.issueClient.AddAssignees(ctx, event.GetIssueOrg(), event.GetIssueRepo(), event.GetIssueNumber(), []string{event.GetIssueUser()})
if response.StatusCode == http.StatusNotFound {
return "", errUnauthorizedClient
}
return event.GetIssueUser(), err
}

207
.github/workflows/dapr-bot/bot_test.go vendored Normal file
View File

@ -0,0 +1,207 @@
package main
import (
"context"
"net/http"
"testing"
"github.com/google/go-github/v55/github"
"github.com/jinzhu/copier"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var testBot = &Bot{
ctx: context.Background(),
issueClient: &testClient{},
}
type testClient struct {
issue *github.Issue
issueComment *github.IssueComment
resp *github.Response
}
func (tc *testClient) CreateComment(ctx context.Context, org, repo string, number int, comment *github.IssueComment) (*github.IssueComment, *github.Response, error) {
return tc.issueComment, tc.resp, nil
}
func (tc *testClient) AddAssignees(ctx context.Context, org, repo string, number int, assignees []string) (*github.Issue, *github.Response, error) {
return tc.issue, tc.resp, nil
}
func TestNewBot(t *testing.T) {
t.Run("create a bot test", func(t *testing.T) {
bot := NewBot(github.NewClient(nil))
assert.NotNil(t, bot)
})
}
func TestHandleEvent(t *testing.T) {
t.Run("handle valid event", func(t *testing.T) {
tc := testClient{
resp: &github.Response{Response: &http.Response{StatusCode: http.StatusOK}},
}
testBot.issueClient = &tc
ctx := context.Background()
var testEventCopy Event
errC := copier.CopyWithOption(&testEventCopy, &testEvent, copier.Option{DeepCopy: true})
if errC != nil {
t.Error(errC)
}
testEventCopy.IssueCommentEvent.Comment.Body = github.String("/assign")
res, err := testBot.HandleEvent(ctx, testEventCopy)
require.NoError(t, err)
assert.NotEmpty(t, res)
})
t.Run("handle valid (longer body) event", func(t *testing.T) {
tc := testClient{
resp: &github.Response{Response: &http.Response{StatusCode: http.StatusOK}},
}
testBot.issueClient = &tc
ctx := context.Background()
var testEventCopy Event
errC := copier.CopyWithOption(&testEventCopy, &testEvent, copier.Option{DeepCopy: true})
if errC != nil {
t.Error(errC)
}
testEventCopy.IssueCommentEvent.Comment.Body = github.String("/assign \r \ntest body")
res, err := testBot.HandleEvent(ctx, testEventCopy)
require.NoError(t, err)
assert.NotEmpty(t, res)
})
t.Run("handle unable to assign", func(t *testing.T) {
tc := testClient{
resp: &github.Response{Response: &http.Response{StatusCode: http.StatusNotFound}},
}
testBot.issueClient = &tc
ctx := context.Background()
var testEventCopy Event
errC := copier.CopyWithOption(&testEventCopy, &testEvent, copier.Option{DeepCopy: true})
if errC != nil {
t.Error(errC)
}
testEventCopy.IssueCommentEvent.Comment.Body = github.String("/assign")
res, err := testBot.HandleEvent(ctx, testEventCopy)
require.Error(t, err)
assert.NotEmpty(t, res)
})
t.Run("handle no event", func(t *testing.T) {
tc := testClient{}
testBot.issueClient = &tc
ctx := context.Background()
var testEventCopy Event
errC := copier.CopyWithOption(&testEventCopy, &testEvent, copier.Option{DeepCopy: true})
if errC != nil {
t.Error(errC)
}
testEventCopy.IssueCommentEvent.Comment.Body = github.String("assign")
res, err := testBot.HandleEvent(ctx, testEventCopy)
require.NoError(t, err)
assert.Equal(t, "no command found", res)
})
}
func TestCreateIssueComment(t *testing.T) {
t.Run("failure to create issue comment", func(t *testing.T) {
tc := testClient{
resp: &github.Response{Response: &http.Response{StatusCode: http.StatusNotFound}},
}
testBot.issueClient = &tc
err := testBot.CreateIssueComment("test", testEvent)
require.Error(t, err)
})
t.Run("create issue comment", func(t *testing.T) {
tc := testClient{
resp: &github.Response{Response: &http.Response{StatusCode: http.StatusOK}},
}
testBot.issueClient = &tc
err := testBot.CreateIssueComment("test", testEvent)
require.NoError(t, err)
})
t.Run("create issue comment with empty body", func(t *testing.T) {
tc := testClient{
resp: &github.Response{Response: &http.Response{StatusCode: http.StatusOK}},
}
testBot.issueClient = &tc
err := testBot.CreateIssueComment("", testEvent)
require.Error(t, err)
})
}
func TestAssignIssueToCommenter(t *testing.T) {
t.Run("failure to assign issue to commenter", func(t *testing.T) {
tc := testClient{
resp: &github.Response{Response: &http.Response{StatusCode: http.StatusNotFound}},
}
testBot.issueClient = &tc
assignee, err := testBot.AssignIssueToCommenter(testEvent)
require.Error(t, err)
assert.Empty(t, assignee)
})
t.Run("successfully assign issue to commenter", func(t *testing.T) {
tc := testClient{
resp: &github.Response{Response: &http.Response{StatusCode: http.StatusOK}},
}
testBot.issueClient = &tc
var testEventCopy Event
errC := copier.CopyWithOption(&testEventCopy, &testEvent, copier.Option{DeepCopy: true})
if errC != nil {
t.Error(errC)
}
testEventCopy.IssueCommentEvent.Issue.Assignees = []*github.User{}
assignee, err := testBot.AssignIssueToCommenter(testEventCopy)
require.NoError(t, err)
assert.Equal(t, "testCommentLogin", assignee)
})
t.Run("attempt to assign a closed issue", func(t *testing.T) {
tc := testClient{}
testBot.issueClient = &tc
var testEventCopy Event
errC := copier.CopyWithOption(&testEventCopy, &testEvent, copier.Option{DeepCopy: true})
if errC != nil {
t.Error(errC)
}
testEventCopy.IssueCommentEvent.Issue.State = github.String("closed")
assignee, err := testBot.AssignIssueToCommenter(testEventCopy)
require.Error(t, err)
assert.Empty(t, assignee)
})
t.Run("issue already assigned to user", func(t *testing.T) {
tc := testClient{}
testBot.issueClient = &tc
var testEventCopy Event
errC := copier.CopyWithOption(&testEventCopy, &testEvent, copier.Option{DeepCopy: true})
if errC != nil {
t.Error(errC)
}
testEventCopy.IssueCommentEvent.Issue.Assignees = []*github.User{{Login: github.String("testCommentLogin")}}
assignee, err := testBot.AssignIssueToCommenter(testEventCopy)
require.Error(t, err)
assert.Empty(t, assignee)
})
t.Run("issue already assigned to another user", func(t *testing.T) {
tc := testClient{
resp: &github.Response{Response: &http.Response{StatusCode: http.StatusOK}},
}
testBot.issueClient = &tc
var testEventCopy Event
errC := copier.CopyWithOption(&testEventCopy, &testEvent, copier.Option{DeepCopy: true})
if errC != nil {
t.Error(errC)
}
testEventCopy.IssueCommentEvent.Issue.Assignees = []*github.User{{Login: github.String("testCommentLogin2")}}
assignee, err := testBot.AssignIssueToCommenter(testEventCopy)
require.Error(t, err)
assert.Empty(t, assignee)
})
}

62
.github/workflows/dapr-bot/event.go vendored Normal file
View File

@ -0,0 +1,62 @@
package main
import (
"encoding/json"
"errors"
"github.com/google/go-github/v55/github"
)
type Event struct {
Type string `json:"type"`
Path string `json:"path"`
IssueCommentEvent *github.IssueCommentEvent `json:"issue_comment_event"`
}
func ProcessEvent(eventType string, eventPath string, data []byte) (e Event, err error) {
var issueCommentEvent *github.IssueCommentEvent
if eventPath == "" {
return Event{}, errors.New("invalid event path")
}
switch eventType {
case "issue_comment":
err = json.Unmarshal(data, &issueCommentEvent)
if err != nil {
return Event{}, err
}
}
e = Event{
Type: eventType,
Path: eventPath,
IssueCommentEvent: issueCommentEvent,
}
return
}
func (e *Event) GetIssueAssignees() []string {
assignees := make([]string, 0)
for _, assignee := range e.IssueCommentEvent.Issue.Assignees {
assignees = append(assignees, assignee.GetLogin())
}
return assignees
}
func (e *Event) GetIssueNumber() int {
return e.IssueCommentEvent.Issue.GetNumber()
}
func (e *Event) GetIssueOrg() string {
return e.IssueCommentEvent.Repo.Owner.GetLogin()
}
func (e *Event) GetIssueRepo() string {
return e.IssueCommentEvent.Repo.GetName()
}
func (e *Event) GetIssueState() string {
return e.IssueCommentEvent.Issue.GetState()
}
func (e *Event) GetIssueUser() string {
return e.IssueCommentEvent.Comment.User.GetLogin()
}

110
.github/workflows/dapr-bot/event_test.go vendored Normal file
View File

@ -0,0 +1,110 @@
package main
import (
"bytes"
"encoding/gob"
"encoding/json"
"testing"
"github.com/google/go-github/v55/github"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var testEvent = Event{
Type: "issue_comment",
Path: "test/test",
IssueCommentEvent: &github.IssueCommentEvent{
Issue: &github.Issue{
Assignees: []*github.User{{Login: github.String("testAssignee")}},
Number: github.Int(123),
State: github.String("testState"),
},
Repo: &github.Repository{
Owner: &github.User{Login: github.String("testOrg")},
Name: github.String("testName"),
},
Comment: &github.IssueComment{
User: &github.User{Login: github.String("testCommentLogin")},
},
},
}
func TestProcessEvent(t *testing.T) {
testEventData, err := json.Marshal(testEvent)
if err != nil {
t.Fatalf("failed to marshal event: %v", err)
}
t.Run("process event", func(t *testing.T) {
event, err := ProcessEvent(testEvent.Type, testEvent.Path, testEventData)
require.NoError(t, err)
assert.NotNil(t, event)
assert.Equal(t, "test/test", event.Path)
})
t.Run("process event with empty path", func(t *testing.T) {
event, err := ProcessEvent(testEvent.Type, "", testEventData)
require.Error(t, err)
assert.Empty(t, event)
})
var randomData bytes.Buffer
encoder := gob.NewEncoder(&randomData)
encoder.Encode("random_data")
t.Run("process issue_comment event", func(t *testing.T) {
event, err := ProcessEvent(testEvent.Type, testEvent.Path, testEventData)
require.NoError(t, err)
assert.NotNil(t, event)
assert.Equal(t, "issue_comment", event.Type)
})
t.Run("process invalid event", func(t *testing.T) {
event, err := ProcessEvent(testEvent.Type, testEvent.Path, randomData.Bytes())
require.Error(t, err)
assert.Empty(t, event)
})
}
func TestGetIssueAssignees(t *testing.T) {
t.Run("get assignees", func(t *testing.T) {
assignees := testEvent.GetIssueAssignees()
assert.Len(t, assignees, 1)
assert.Equal(t, "testAssignee", assignees[0])
})
}
func TestGetIssueNumber(t *testing.T) {
t.Run("get issue number", func(t *testing.T) {
number := testEvent.GetIssueNumber()
assert.Equal(t, 123, number)
})
}
func TestGetIssueOrg(t *testing.T) {
t.Run("get issue org", func(t *testing.T) {
org := testEvent.GetIssueOrg()
assert.Equal(t, "testOrg", org)
})
}
func TestGetIssueRepo(t *testing.T) {
t.Run("get issue repo", func(t *testing.T) {
repo := testEvent.GetIssueRepo()
assert.Equal(t, "testName", repo)
})
}
func TestGetIssueState(t *testing.T) {
t.Run("get issue state", func(t *testing.T) {
state := testEvent.GetIssueState()
assert.Equal(t, "testState", state)
})
}
func TestGetIssueUser(t *testing.T) {
t.Run("get issue user", func(t *testing.T) {
user := testEvent.GetIssueUser()
assert.Equal(t, "testCommentLogin", user)
})
}

20
.github/workflows/dapr-bot/go.mod vendored Normal file
View File

@ -0,0 +1,20 @@
module github.com/dapr/go-sdk/.github/workflows/dapr-bot
go 1.23.3
require (
github.com/google/go-github/v55 v55.0.0
github.com/jinzhu/copier v0.4.0
github.com/stretchr/testify v1.8.4
)
require (
github.com/ProtonMail/go-crypto v1.0.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/sys v0.16.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

71
.github/workflows/dapr-bot/go.sum vendored Normal file
View File

@ -0,0 +1,71 @@
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg=
github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

37
.github/workflows/dapr-bot/main.go vendored Normal file
View File

@ -0,0 +1,37 @@
package main
import (
"context"
"log"
"os"
"github.com/google/go-github/v55/github"
)
func main() {
ctx := context.Background()
githubToken := os.Getenv("GITHUB_TOKEN")
if githubToken == "" {
log.Fatal("GITHUB_TOKEN is required")
}
ghClient := github.NewClient(nil).WithAuthToken(githubToken)
bot := NewBot(ghClient)
eventType := os.Getenv("GITHUB_EVENT_NAME")
eventPath := os.Getenv("GITHUB_EVENT_PATH")
data, err := os.ReadFile(eventPath)
if err != nil {
log.Fatalf("failed to read event: %v", err)
}
event, err := ProcessEvent(eventType, eventPath, data)
if err != nil {
log.Fatalf("failed to process event: %v", err)
}
log.Printf("processing event: %s", event.Type)
res, err := bot.HandleEvent(ctx, event)
if err != nil {
log.Fatalf("failed to handle event: %v", err)
}
log.Println(res)
}

View File

@ -32,15 +32,15 @@ jobs:
FOSSA_API_KEY: b88e1f4287c3108c8751bf106fb46db6 # This is a push-only token that is safe to be exposed.
steps:
- name: "Checkout code"
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: "Run FOSSA Scan"
uses: fossas/fossa-action@v1.1.0 # Use a specific version if locking is preferred
uses: fossas/fossa-action@v1.3.3 # Use a specific version if locking is preferred
with:
api-key: ${{ env.FOSSA_API_KEY }}
- name: "Run FOSSA Test"
uses: fossas/fossa-action@v1.1.0 # Use a specific version if locking is preferred
uses: fossas/fossa-action@v1.3.3 # Use a specific version if locking is preferred
with:
api-key: ${{ env.FOSSA_API_KEY }}
run-tests: true

View File

@ -3,59 +3,70 @@ name: Release
on:
push:
tags:
- 'v*' # v0.8.1
- "v*" # v0.8.1
jobs:
build:
name: Create Release on Tag
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup
uses: actions/setup-go@v3
with:
go-version: ^1.19
- name: Setup
uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
- name: Checkout
uses: actions/checkout@v3
- name: Check sdk-version file
run: |
SDK_VERSION="$(head -n1 version/sdk-version)"
SDK_VERSION_GIT="refs/tags/${SDK_VERSION}"
if [[ "${SDK_VERSION_GIT}" != "${{ github.ref }}" ]]; then
echo "File version/sdk-version (${SDK_VERSION}) needs to be updated to ${{ github.ref }}"
exit 1
fi
shell: bash
- name: Check sdk-version file
run: |
SDK_VERSION="$(head -n1 version/sdk-version)"
SDK_VERSION_GIT="refs/tags/${SDK_VERSION}"
if [[ "${SDK_VERSION_GIT}" != "${{ github.ref }}" ]]; then
echo "File version/sdk-version (${SDK_VERSION}) needs to be updated to ${{ github.ref }}"
exit 1
fi
shell: bash
- name: Tidy
run: make tidy
- name: Tidy
run: make tidy
- name: Test
run: make test
- name: Test
run: make test
- name: Version
run: |
echo "RELEASE_VERSION=$(echo ${GITHUB_REF:10})" >> $GITHUB_ENV
- name: Version
run: |
echo "RELEASE_VERSION=$(echo ${GITHUB_REF:10})" >> $GITHUB_ENV
- name: Release Main
uses: actions/create-release@v1
if: ${{ !contains(github.ref , 'rc') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body: Automatic Go Dapr client release
draft: false
prerelease: false
- name: Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body: Automatic Go Dapr client release
draft: false
prerelease: false
- name: Release RC
uses: actions/create-release@v1
if: ${{ contains(github.ref, 'rc') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body: Automatic Go Dapr client release
draft: false
prerelease: true
- name: Notify
uses: rjstone/discord-webhook-notify@v1
with:
severity: info
details: Release ${{ github.ref }} published
description: Release
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
avatarUrl: https://github.githubassets.com/images/modules/logos_page/Octocat.png
- name: Notify
uses: rjstone/discord-webhook-notify@v1
with:
severity: info
details: Release ${{ github.ref }} published
description: Release
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
avatarUrl: https://github.githubassets.com/images/modules/logos_page/Octocat.png

45
.github/workflows/test-dapr-bot.yml vendored Normal file
View File

@ -0,0 +1,45 @@
name: Test Dapr-Bot
on:
push:
paths: # Explicitly declare which paths
- ".github/workflows/dapr-bot.yml"
- ".github/workflows/dapr-bot/*"
pull_request:
branches:
- main
paths: # Explicitly declare which paths
- ".github/workflows/dapr-bot.yml"
- ".github/workflows/dapr-bot/*"
jobs:
build:
name: Test
runs-on: ubuntu-latest
env:
GOLANGCILINT_VER: v1.64.6
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup
uses: actions/setup-go@v5
with:
go-version-file: ./.github/workflows/dapr-bot/go.mod
- name: Tidy
working-directory: ./.github/workflows/dapr-bot
run: make tidy
- name: Test
working-directory: ./.github/workflows/dapr-bot
run: make test
- name: Lint
uses: golangci/golangci-lint-action@v6
with:
version: ${{ env.GOLANGCILINT_VER }}
working-directory: ./.github/workflows/dapr-bot
skip-cache: true
args: --timeout=10m0s --config ../../../.golangci.yml

View File

@ -8,34 +8,21 @@ on:
jobs:
build:
name: Test on ${{ matrix.gover }}
name: Test
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
gover:
- "1.19"
- "1.20"
env:
GOVER: ${{ matrix.gover }}
GOLANGCILINT_VER: v1.54.2
GOLANGCILINT_VER: v1.64.6
steps:
- name: Setup
uses: actions/setup-go@v3
with:
go-version: ${{ env.GOVER }}
- name: Checkout
uses: actions/checkout@v3
- name: Cache
uses: actions/cache@v3
uses: actions/checkout@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
submodules: recursive
- name: Setup
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
- name: Tidy
run: make tidy
@ -44,10 +31,10 @@ jobs:
run: make test
- name: Cover
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
- name: Lint
uses: golangci/golangci-lint-action@v3.3.1
uses: golangci/golangci-lint-action@v6
with:
version: ${{ env.GOLANGCILINT_VER }}
skip-cache: true
@ -55,3 +42,5 @@ jobs:
- name: Run go mod tidy check diff
run: make modtidy check-diff
- name: Run go mod tidy
run: make modtidy

56
.github/workflows/test-tooling.yml vendored Normal file
View File

@ -0,0 +1,56 @@
name: Test Tooling
on:
push:
paths: # Explicitly declare which paths
- ".github/workflows/test-tooling.yml"
- "tools/*"
pull_request:
branches:
- main
paths: # Explicitly declare which paths
- ".github/workflows/test-tooling.yml"
- "tools/*"
jobs:
build:
name: Test (${{ matrix.os}}) go ${{ matrix.gover }}
strategy:
fail-fast: false
matrix:
os:
- "ubuntu-latest"
- "windows-latest"
- "macos-latest"
runs-on: ${{ matrix.os }}
env:
GOLANGCILINT_VER: v1.64.6 # Make sure to bump /tools/check-lint-version/main_test.go
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup
uses: actions/setup-go@v5
with:
go-version-file: ./tools/check-lint-version/go.mod
- name: Tidy
working-directory: ./tools/check-lint-version
run: make tidy
- name: Lint
uses: golangci/golangci-lint-action@v6
with:
version: ${{ env.GOLANGCILINT_VER }}
working-directory: ./tools/check-lint-version
skip-cache: true
args: --timeout=10m0s --config ../../.golangci.yml
- name: Install Linter
run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "$(go env GOPATH)/bin" ${{ env.GOLANGCILINT_VER }}
- name: Test
working-directory: ./tools/check-lint-version
run: make test

View File

@ -4,97 +4,242 @@ on:
push:
branches:
- main
- release-*
tags:
- v*
pull_request:
branches:
- main
- release-*
workflow_dispatch:
inputs:
daprdapr_commit:
description: "Dapr/Dapr commit to build custom daprd from"
required: false
default: ""
daprcli_commit:
description: "Dapr/CLI commit to build custom dapr CLI from"
required: false
default: ""
repository_dispatch:
types: [validate-examples]
merge_group:
jobs:
validate:
setup:
runs-on: ubuntu-latest
env:
PYTHON_VER: 3.7
GOVER: "1.20"
GOOS: linux
GOARCH: amd64
GOPROXY: https://proxy.golang.org
DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/master/install/install.sh
DAPR_CLI_REF: ""
DAPR_REF: 770d4e51604f1264d8bb25cedf16ea9f77539394
DAPR_CLI_REF: ${{ github.event.inputs.daprcli_commit }}
DAPR_REF: ${{ github.event.inputs.daprdapr_commit }}
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_REF: ${{ github.ref }}
outputs:
DAPR_INSTALL_URL: ${{ env.DAPR_INSTALL_URL }}
DAPR_CLI_VER: ${{ steps.outputs.outputs.DAPR_CLI_VER }}
DAPR_CLI_REF: ${{ steps.outputs.outputs.DAPR_CLI_REF }}
DAPR_RUNTIME_VER: ${{ steps.outputs.outputs.DAPR_RUNTIME_VER }}
CHECKOUT_REPO: ${{ steps.outputs.outputs.CHECKOUT_REPO }}
CHECKOUT_REF: ${{ steps.outputs.outputs.CHECKOUT_REF }}
DAPR_REF: ${{ steps.outputs.outputs.DAPR_REF }}
GITHUB_SHA: ${{ steps.outputs.outputs.GITHUB_SHA }}
steps:
- uses: actions/checkout@v3
- name: Parse repository_dispatch payload
if: github.event_name == 'repository_dispatch'
run: |
if [ ${{ github.event.client_payload.command }} = "ok-to-test" ]; then
echo "CHECKOUT_REPO=${{ github.event.client_payload.pull_head_repo }}" >> $GITHUB_ENV
echo "CHECKOUT_REF=${{ github.event.client_payload.pull_head_ref }}" >> $GITHUB_ENV
echo "DAPR_REF=master" >> $GITHUB_ENV
fi
- name: Check out code onto GOPATH
uses: actions/checkout@v4
with:
repository: ${{ env.CHECKOUT_REPO }}
ref: ${{ env.CHECKOUT_REF }}
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
- name: Run go mod tidy check diff
run: make modtidy check-diff
- name: Determine latest Dapr Runtime version
run: |
RUNTIME_VERSION=$(curl -s "https://api.github.com/repos/dapr/dapr/releases/latest" | grep '"tag_name"' | cut -d ':' -f2 | tr -d '",v')
echo "DAPR_RUNTIME_VER=$RUNTIME_VERSION" >> $GITHUB_ENV
echo "Found $RUNTIME_VERSION"
- name: Determine latest Dapr Cli version
run: |
CLI_VERSION=$(curl -s "https://api.github.com/repos/dapr/cli/releases/latest" | grep '"tag_name"' | cut -d ':' -f2 | tr -d '",v')
echo "DAPR_CLI_VER=$CLI_VERSION" >> $GITHUB_ENV
echo "Found $CLI_VERSION"
- name: Set up Python ${{ env.PYTHON_VER }}
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VER }}
- name: Install Mechanical Markdown
run: |
python -m pip install --upgrade pip
pip install mechanical-markdown
- name: Run go mod tidy check diff
run: make modtidy check-diff
- name: Set up Dapr CLI
run: wget -q ${{ env.DAPR_INSTALL_URL }} -O - | /bin/bash -s ${{ env.DAPR_CLI_VER }}
- name: Set up Go ${{ env.GOVER }}
if: env.DAPR_REF != '' || env.DAPR_CLI_REF != ''
uses: actions/setup-go@v3
with:
go-version: ${{ env.GOVER }}
- name: Checkout Dapr CLI repo to override dapr command.
uses: actions/checkout@v3
uses: actions/checkout@v4
if: env.DAPR_CLI_REF != ''
with:
repository: dapr/cli
ref: ${{ env.DAPR_CLI_REF }}
path: cli
- name: Checkout Dapr repo to override daprd.
uses: actions/checkout@v3
uses: actions/checkout@v4
if: env.DAPR_REF != ''
with:
repository: dapr/dapr
ref: ${{ env.DAPR_REF }}
path: dapr_runtime
- name: Build and override dapr cli with referenced commit.
- name: Build dapr cli with referenced commit.
if: env.DAPR_CLI_REF != ''
run: |
echo "artifactPath=~/artifacts/$GITHUB_SHA/" >> $GITHUB_ENV
cd cli
make
sudo cp dist/linux_amd64/release/dapr /usr/local/bin/dapr
cd ..
mkdir -p $HOME/artifacts/$GITHUB_SHA/
sudo cp dist/linux_amd64/release/dapr ~/artifacts/$GITHUB_SHA/dapr
echo "artifactPath=~/artifacts/$GITHUB_SHA/" >> $GITHUB_ENV
echo "DAPR_CLI_REF=$DAPR_CLI_REF" >> $GITHUB_ENV
- name: Build dapr
if: env.DAPR_REF != ''
run: |
echo "artifactPath=~/artifacts/$GITHUB_SHA/" >> $GITHUB_ENV
cd dapr_runtime
make
mkdir -p $HOME/artifacts/$GITHUB_SHA/
echo "artifactPath=~/artifacts/$GITHUB_SHA/" >> $GITHUB_ENV
cp ./dist/linux_amd64/release/* ~/artifacts/$GITHUB_SHA/
- name: Upload dapr-artifacts
uses: actions/upload-artifact@v4
if: env.DAPR_REF != '' || env.DAPR_CLI_REF != ''
with:
name: dapr-artifacts
path: ${{ env.artifactPath }}
if-no-files-found: error
retention-days: 1
compression-level: 0
- name: Outputs
id: outputs
run: |
echo "DAPR_INSTALL_URL=$DAPR_INSTALL_URL"
echo "DAPR_CLI_VER=$DAPR_CLI_VER" >> "$GITHUB_OUTPUT"
echo "DAPR_CLI_REF=$DAPR_CLI_REF" >> "$GITHUB_OUTPUT"
echo "DAPR_RUNTIME_VER=$DAPR_RUNTIME_VER" >> "$GITHUB_OUTPUT"
echo "CHECKOUT_REPO=$CHECKOUT_REPO" >> "$GITHUB_OUTPUT"
echo "CHECKOUT_REF=$CHECKOUT_REF" >> "$GITHUB_OUTPUT"
echo "DAPR_REF=$DAPR_REF" >> "$GITHUB_OUTPUT"
echo "GITHUB_SHA=$GITHUB_SHA" >> "$GITHUB_OUTPUT"
validate-example:
needs: setup
runs-on: ubuntu-latest
env:
PYTHON_VER: 3.12
GOOS: linux
GOARCH: amd64
GOPROXY: https://proxy.golang.org
DAPR_INSTALL_URL: ${{ needs.setup.outputs.DAPR_INSTALL_URL }}
DAPR_CLI_VER: ${{ needs.setup.outputs.DAPR_CLI_VER }}
DAPR_RUNTIME_VER: ${{ needs.setup.outputs.DAPR_RUNTIME_VER }}
DAPR_CLI_REF: ${{ needs.setup.outputs.DAPR_CLI_REF }}
DAPR_REF: ${{ needs.setup.outputs.DAPR_REF }}
CHECKOUT_REPO: ${{ needs.setup.outputs.CHECKOUT_REPO }}
CHECKOUT_REF: ${{ needs.setup.outputs.CHECKOUT_REF }}
GITHUB_SHA: ${{ needs.setup.outputs.GITHUB_SHA }}
strategy:
fail-fast: false
matrix:
examples:
[
"actor",
"configuration",
"conversation",
"crypto",
"dist-scheduler",
"grpc-service",
"hello-world",
"pubsub",
"streamsub",
"service",
"socket",
"workflow",
"workflow-parallel",
]
steps:
- name: Check out code onto GOPATH
uses: actions/checkout@v4
with:
repository: ${{ env.CHECKOUT_REPO }}
ref: ${{ env.CHECKOUT_REF }}
- name: Make Artifacts destination folder
if: env.DAPR_CLI_REF != '' || env.DAPR_REF != ''
run: |
mkdir -p $HOME/artifacts/$GITHUB_SHA/
- name: Retrieve dapr-artifacts
if: env.DAPR_CLI_REF != '' || env.DAPR_REF != ''
uses: actions/download-artifact@v4
with:
name: dapr-artifacts
path: ~/artifacts/${{ env.GITHUB_SHA }}/
- name: Display artifacts downloaded
if: env.DAPR_CLI_REF != '' || env.DAPR_REF != ''
run: ls ~/artifacts/$GITHUB_SHA/
- name: Set up Go
id: setup-go
uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
- name: Set up Dapr CLI
if: env.DAPR_CLI_VER != ''
run: wget -q ${{ env.DAPR_INSTALL_URL }} -O - | /bin/bash -s ${{ env.DAPR_CLI_VER }}
- name: Override dapr cli with referenced commit.
if: env.DAPR_CLI_REF != ''
run: |
sudo cp $HOME/artifacts/$GITHUB_SHA/dapr /usr/local/bin/dapr
- name: Initialize Dapr runtime ${{ env.DAPR_RUNTIME_VER }}
run: |
dapr uninstall --all
dapr init --runtime-version ${{ env.DAPR_RUNTIME_VER }}
- name: Build and override daprd with referenced commit.
- name: Print scheduler logs
run: |
docker logs dapr_scheduler
- name: Override daprd with referenced commit.
if: env.DAPR_REF != ''
run: |
cd dapr_runtime
make
mkdir -p $HOME/.dapr/bin/
cp dist/linux_amd64/release/daprd $HOME/.dapr/bin/daprd
cd ..
- name: Override placement service.
if: env.DAPR_REF != ''
cp $HOME/artifacts/$GITHUB_SHA/daprd $HOME/.dapr/bin/daprd
- name: Set up Python ${{ env.PYTHON_VER }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VER }}
- name: Install Mechanical Markdown
run: |
docker stop dapr_placement
cd dapr_runtime
./dist/linux_amd64/release/placement --healthz-port 9091 &
- name: Check Examples
python -m pip install --upgrade pip
pip install mechanical-markdown
- name: Check Example
run: |
cd examples
./validate.sh grpc-service
./validate.sh configuration
./validate.sh hello-world
./validate.sh pubsub
./validate.sh service
./validate.sh actor
./validate.sh ${{ matrix.examples }}

View File

@ -4,7 +4,7 @@ run:
concurrency: 4
# timeout for analysis, e.g. 30s, 5m, default is 1m
deadline: 10m
timeout: 15m
# exit code when at least one issue was found, default is 1
issues-exit-code: 1
@ -13,31 +13,35 @@ run:
tests: true
# list of build tags, all linters use it. Default is empty list.
#build-tags:
# - mytag
# which dirs to skip: they won't be analyzed;
# can use regexp here: generated.*, regexp is applied on full path;
# default value is empty list, but next dirs are always skipped independently
# from this option's value:
# third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs:
- ^pkg.*client.*clientset.*versioned.*
- ^pkg.*client.*informers.*externalversions.*
- ^pkg.*proto.*
build-tags:
- unit
- allcomponents
- subtlecrypto
# which files to skip: they will be analyzed, but issues from them
# won't be reported. Default value is empty list, but there is
# no need to include all autogenerated files, we confidently recognize
# autogenerated files. If it's not please let us know.
# skip-files:
# skip-files:
# - ".*\\.my\\.go$"
# - lib/bad.go
issues:
# which dirs to skip: they won't be analyzed;
# can use regexp here: generated.*, regexp is applied on full path;
# default value is empty list, but next dirs are always skipped independently
# from this option's value:
# third_party$, testdata$, examples$, Godeps$, builtin$
exclude-dirs:
- ^pkg.*client.*clientset.*versioned.*
- ^pkg.*client.*informers.*externalversions.*
- ^pkg.*proto.*
# output configuration options
output:
# colored-line-number|line-number|json|tab|checkstyle, default is "colored-line-number"
format: tab
formats:
- format: tab
# print lines of code with issue, default is true
print-issued-lines: true
@ -57,23 +61,19 @@ linters-settings:
# default is false: such cases aren't reported by default.
check-blank: false
# [deprecated] comma-separated list of pairs of the form pkg:regex
# the regex is used to ignore names within pkg. (default "fmt:.*").
# see https://github.com/kisielk/errcheck#the-deprecated-method for details
ignore: fmt:.*,io/ioutil:^Read.*
exclude-functions:
- fmt:.*
- io/ioutil:^Read.*
# path to a file containing a list of functions to exclude from checking
# see https://github.com/kisielk/errcheck#excluding-functions for details
# exclude:
# exclude:
funlen:
lines: 60
statements: 40
govet:
# report about shadowed variables
check-shadowing: true
# settings per analyzer
settings:
printf: # analyzer name, run `go tool vet help` to see all analyzers
@ -86,28 +86,12 @@ linters-settings:
# enable or disable analyzers by name
enable:
- atomicalign
enable-all: false
disable:
- shadow
enable-all: false
disable-all: false
revive:
max-open-files: 2048
# enable-all-rules: true
rules:
- name: cyclomatic
severity: warning
disabled: false
arguments: [20]
- name: argument-limit
severity: warning
disabled: false
arguments: [8]
- name: if-return
severity: warning
disabled: false
- name: unused-parameter
severity: warning
disabled: true
# minimal confidence for issues, default is 0.8
confidence: 0.8
gofmt:
# simplify code: gofmt with `-s` option, true by default
simplify: true
@ -121,9 +105,6 @@ linters-settings:
gocognit:
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 10
maligned:
# print struct with more effective memory layout or not, false by default
suggest-new: true
dupl:
# tokens count to trigger issue, 150 by default
threshold: 100
@ -152,10 +133,9 @@ linters-settings:
desc: "you must use github.com/cenkalti/backoff/v4"
misspell:
# Correct spellings using locale preferences for US or UK.
# Default is to use a neutral variety of English. (Do not specify a locale value)
# Default is to use a neutral variety of English.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
# locale:
# locale: default
ignore-words:
- someword
lll:
@ -164,18 +144,6 @@ linters-settings:
line-length: 120
# tab width in spaces. Default to 1.
tab-width: 1
unused:
# treat code as a program (not a library) and report unused exported identifiers; default is false.
# XXX: if you enable this setting, unused will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find funcs usages. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
unparam:
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find external interfaces. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
nakedret:
# make an issue if func has more lines of code than this setting and it has naked returns; default is 30
max-func-lines: 30
@ -193,7 +161,7 @@ linters-settings:
# See https://go-critic.github.io/overview#checks-overview
# To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run`
# By default list of stable checks is used.
# enabled-checks:
# enabled-checks:
# Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty
disabled-checks:
@ -241,17 +209,20 @@ linters-settings:
allow-assign-and-call: true
# Allow multiline assignments to be cuddled. Default is true.
allow-multiline-assign: true
# Allow case blocks to end with a whitespace.
allow-case-traling-whitespace: true
# Allow declarations (var) to be cuddled.
allow-cuddle-declarations: false
# If the number of lines in a case block is equal to or lager than this number,
# the case *must* end white a newline.
# https://github.com/bombsimon/wsl/blob/master/doc/configuration.md#force-case-trailing-whitespace
# Default: 0
force-case-trailing-whitespace: 1
linters:
fast: false
enable-all: true
disable:
# TODO Enforce the below linters later
- nosnakecase
- musttag
- dupl
- errcheck
- funlen
@ -260,26 +231,16 @@ linters:
- gocyclo
- gocognit
- godox
- interfacer
- lll
- maligned
- scopelint
- unparam
- wsl
- gomnd
- testpackage
- goerr113
- nestif
- nlreturn
- tagliatelle
- ifshort
- forbidigo
- exhaustive
- exhaustruct
- exhaustivestruct
- noctx
- gci
- golint
- tparallel
- paralleltest
- wrapcheck
@ -293,7 +254,6 @@ linters:
- varnamelen
- errorlint
- forcetypeassert
- ifshort
- maintidx
- nilnil
- predeclared
@ -306,13 +266,10 @@ linters:
- asasalint
- rowserrcheck
- sqlclosecheck
- structcheck
- varcheck
- deadcode
- golint
issues:
exclude-rules:
- path: .*_test.go
linters:
- godot
- inamedparam
- tagalign
- mnd
- canonicalheader
- err113
- fatcontext
- forbidigo # TODO: Re-enable and remove fmt.println

View File

@ -1,6 +1,6 @@
RELEASE_VERSION =v1.0.0-rc-3
GDOC_PORT =8888
GO_COMPAT_VERSION=1.19
GO_COMPAT_VERSION=1.22
.PHONY: all
all: help
@ -11,7 +11,7 @@ tidy: ## Updates the go modules
.PHONY: test
test:
go test -count=1 \
CGO_ENABLED=1 go test -count=1 \
-race \
-coverprofile=coverage.txt \
-covermode=atomic \
@ -27,11 +27,22 @@ cover: ## Displays test coverage in the client and service packages
go test -coverprofile=cover-client.out ./client && go tool cover -html=cover-client.out
go test -coverprofile=cover-grpc.out ./service/grpc && go tool cover -html=cover-grpc.out
go test -coverprofile=cover-http.out ./service/http && go tool cover -html=cover-http.out
go test -coverprofile=cover-workflow.out ./workflow && go tool cover -html=cover-workflow.out
.PHONY: lint
lint: ## Lints the entire project
lint: check-lint ## Lints the entire project
golangci-lint run --timeout=3m
.PHONY: lint-fix
lint-fix: check-lint ## Lints the entire project
golangci-lint run --timeout=3m --fix
.PHONY: check-lint
check-lint: ## Compares the locally installed linter with the workflow version
cd ./tools/check-lint-version && \
go mod tidy && \
go run main.go
.PHONY: tag
tag: ## Creates release tag
git tag $(RELEASE_VERSION)

View File

@ -292,6 +292,50 @@ func main() {
}
```
##### Error handling
Dapr errors are based on [gRPC's richer error model](https://cloud.google.com/apis/design/errors#error_model).
The following code shows how to parse and handle the error details:
```go
if err != nil {
st := status.Convert(err)
fmt.Printf("Code: %s\n", st.Code().String())
fmt.Printf("Message: %s\n", st.Message())
for _, detail := range st.Details() {
switch t := detail.(type) {
case *errdetails.ErrorInfo:
// Handle ErrorInfo details
fmt.Printf("ErrorInfo:\n- Domain: %s\n- Reason: %s\n- Metadata: %v\n", t.GetDomain(), t.GetReason(), t.GetMetadata())
case *errdetails.BadRequest:
// Handle BadRequest details
fmt.Println("BadRequest:")
for _, violation := range t.GetFieldViolations() {
fmt.Printf("- Key: %s\n", violation.GetField())
fmt.Printf("- The %q field was wrong: %s\n", violation.GetField(), violation.GetDescription())
}
case *errdetails.ResourceInfo:
// Handle ResourceInfo details
fmt.Printf("ResourceInfo:\n- Resource type: %s\n- Resource name: %s\n- Owner: %s\n- Description: %s\n",
t.GetResourceType(), t.GetResourceName(), t.GetOwner(), t.GetDescription())
case *errdetails.Help:
// Handle ResourceInfo details
fmt.Println("HelpInfo:")
for _, link := range t.GetLinks() {
fmt.Printf("- Url: %s\n", link.Url)
fmt.Printf("- Description: %s\n", link.Description)
}
default:
// Add cases for other types of details you expect
fmt.Printf("Unhandled error detail type: %v\n", t)
}
}
}
```
### Service (callback)
In addition to the client capabilities that allow you to call into the Dapr API, the Go SDK also provides `service` package to help you bootstrap Dapr callback services in either gRPC or HTTP. Instructions on how to use it are located [here](./service/Readme.md).

View File

@ -72,7 +72,7 @@ func TestContainerInvoke(t *testing.T) {
mockCodec.EXPECT().Unmarshal([]byte(param), gomock.Any()).SetArg(1, "param").Return(nil)
rsp, err := container.Invoke("Invoke", []byte(param))
require.Equal(t, 2, len(rsp))
require.Len(t, rsp, 2)
require.Equal(t, actorErr.Success, err)
assert.Equal(t, param, rsp[0].Interface().(string))
}

View File

@ -19,6 +19,7 @@ import (
"fmt"
"log"
"reflect"
"slices"
"sync"
"unicode"
"unicode/utf8"
@ -29,6 +30,22 @@ import (
actorErr "github.com/dapr/go-sdk/actor/error"
)
// ignoredActorMethods is a list of method names that should be ignored during actor method reflection.
// It is initialized with the Type() method which is needed to comply with the ServerContext interface.
var ignoredActorMethods = []string{"Type"}
// init initializes the action method exclusion list with methods from ServerImplBaseCtx and ReminderCallee interfaces.
func init() {
serverImplBaseCtxType := reflect.TypeOf(&actor.ServerImplBaseCtx{})
for i := range serverImplBaseCtxType.NumMethod() {
ignoredActorMethods = append(ignoredActorMethods, serverImplBaseCtxType.Method(i).Name)
}
ReminderCallType := reflect.TypeOf((*actor.ReminderCallee)(nil)).Elem()
for i := range ReminderCallType.NumMethod() {
ignoredActorMethods = append(ignoredActorMethods, ReminderCallType.Method(i).Name)
}
}
type ActorManager interface {
RegisterActorImplFactory(f actor.Factory)
InvokeMethod(actorID, methodName string, request []byte) ([]byte, actorErr.ActorErr)
@ -248,8 +265,12 @@ type MethodType struct {
// suitableMethods returns suitable Rpc methods of typ.
func suitableMethods(typ reflect.Type) map[string]*MethodType {
methods := make(map[string]*MethodType)
for m := 0; m < typ.NumMethod(); m++ {
for m := range typ.NumMethod() {
method := typ.Method(m)
// skip methods from ServerImplBaseCtx struct and ServerContext and ReminderCallee interfaces.
if slices.Contains(ignoredActorMethods, method.Name) {
continue
}
if mt, err := suiteMethod(method); err != nil {
log.Printf("method %s is illegal, err = %s, just skip it", method.Name, err)
} else {

View File

@ -256,16 +256,16 @@ func (mr *MockServerContextMockRecorder) Type() *gomock.Call {
}
func (mr *MockServerContextMockRecorder) Invoke(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Invoke", reflect.TypeOf((*MockServerContext)(nil).Invoke), arg0, arg1)
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Invoke", reflect.TypeOf((*MockServerContext)(nil).Invoke), arg0, arg1)
}
func (m *MockServerContext) Invoke(ctx context.Context, input string) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Invoke", ctx, input)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Invoke", ctx, input)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// MockReminderCallee is a mock of ReminderCallee interface.

View File

@ -48,6 +48,7 @@ func TestRegisterActorFactoryAndInvokeMethod(t *testing.T) {
mockServer.EXPECT().RegisterActorImplFactory(gomock.Any())
rt.RegisterActorFactory(actorMock.ActorImplFactory)
//nolint:usetesting
mockServer.EXPECT().InvokeMethod(context.Background(), "mockActorID", "Invoke", []byte("param")).Return([]byte("response"), actorErr.Success)
rspData, err := rt.InvokeActorMethod("testActorType", "mockActorID", "Invoke", []byte("param"))
@ -89,6 +90,7 @@ func TestInvokeReminder(t *testing.T) {
mockServer.EXPECT().RegisterActorImplFactory(gomock.Any())
rt.RegisterActorFactory(actorMock.ActorImplFactory)
//nolint:usetesting
mockServer.EXPECT().InvokeReminder(context.Background(), "mockActorID", "mockReminder", []byte("param")).Return(actorErr.Success)
err = rt.InvokeReminder("testActorType", "mockActorID", "mockReminder", []byte("param"))
@ -109,6 +111,7 @@ func TestInvokeTimer(t *testing.T) {
mockServer.EXPECT().RegisterActorImplFactory(gomock.Any())
rt.RegisterActorFactory(actorMock.ActorImplFactory)
//nolint:usetesting
mockServer.EXPECT().InvokeTimer(context.Background(), "mockActorID", "mockTimer", []byte("param")).Return(actorErr.Success)
err = rt.InvokeTimer("testActorType", "mockActorID", "mockTimer", []byte("param"))

View File

@ -46,7 +46,6 @@ func TestNewActorStateChange(t *testing.T) {
},
}
for name, test := range tests {
test := test
t.Run(name, func(t *testing.T) {
assert.Equal(t, test.want, NewActorStateChange(test.stateName, test.value, test.changeKind, &test.ttl))
})

View File

@ -20,7 +20,7 @@ import (
"reflect"
"strconv"
anypb "github.com/golang/protobuf/ptypes/any"
"google.golang.org/protobuf/types/known/anypb"
pb "github.com/dapr/dapr/pkg/proto/runtime/v1"
"github.com/dapr/go-sdk/actor"
@ -66,7 +66,7 @@ func (c *GRPCClient) InvokeActor(ctx context.Context, in *InvokeActorRequest) (o
Data: in.Data,
}
resp, err := c.protoClient.InvokeActor(c.withAuthToken(ctx), req)
resp, err := c.protoClient.InvokeActor(ctx, req)
if err != nil {
return nil, fmt.Errorf("error invoking binding %s/%s: %w", in.ActorType, in.ActorID, err)
}
@ -74,7 +74,7 @@ func (c *GRPCClient) InvokeActor(ctx context.Context, in *InvokeActorRequest) (o
out = &InvokeActorResponse{}
if resp != nil {
out.Data = resp.Data
out.Data = resp.GetData()
}
return out, nil
@ -153,7 +153,7 @@ func (c *GRPCClient) RegisterActorReminder(ctx context.Context, in *RegisterActo
Data: in.Data,
}
_, err = c.protoClient.RegisterActorReminder(c.withAuthToken(ctx), req)
_, err = c.protoClient.RegisterActorReminder(ctx, req)
if err != nil {
return fmt.Errorf("error invoking register actor reminder %s/%s: %w", in.ActorType, in.ActorID, err)
}
@ -187,52 +187,13 @@ func (c *GRPCClient) UnregisterActorReminder(ctx context.Context, in *Unregister
Name: in.Name,
}
_, err := c.protoClient.UnregisterActorReminder(c.withAuthToken(ctx), req)
_, err := c.protoClient.UnregisterActorReminder(ctx, req)
if err != nil {
return fmt.Errorf("error invoking unregister actor reminder %s/%s: %w", in.ActorType, in.ActorID, err)
}
return nil
}
type RenameActorReminderRequest struct {
OldName string
ActorType string
ActorID string
NewName string
}
// RenameActorReminder would rename the actor reminder.
func (c *GRPCClient) RenameActorReminder(ctx context.Context, in *RenameActorReminderRequest) error {
if in == nil {
return errors.New("actor rename reminder invocation request param required")
}
if in.ActorType == "" {
return errors.New("actor rename reminder invocation actorType required")
}
if in.ActorID == "" {
return errors.New("actor rename reminder invocation actorID required")
}
if in.OldName == "" {
return errors.New("actor rename reminder invocation oldName required")
}
if in.NewName == "" {
return errors.New("actor rename reminder invocation newName required")
}
req := &pb.RenameActorReminderRequest{
ActorType: in.ActorType,
ActorId: in.ActorID,
OldName: in.OldName,
NewName: in.NewName,
}
_, err := c.protoClient.RenameActorReminder(c.withAuthToken(ctx), req)
if err != nil {
return fmt.Errorf("error invoking rename actor reminder %s/%s: %w", in.ActorType, in.ActorID, err)
}
return nil
}
type RegisterActorTimerRequest struct {
ActorType string
ActorID string
@ -274,7 +235,7 @@ func (c *GRPCClient) RegisterActorTimer(ctx context.Context, in *RegisterActorTi
Callback: in.CallBack,
}
_, err = c.protoClient.RegisterActorTimer(c.withAuthToken(ctx), req)
_, err = c.protoClient.RegisterActorTimer(ctx, req)
if err != nil {
return fmt.Errorf("error invoking actor register timer %s/%s: %w", in.ActorType, in.ActorID, err)
}
@ -308,7 +269,7 @@ func (c *GRPCClient) UnregisterActorTimer(ctx context.Context, in *UnregisterAct
Name: in.Name,
}
_, err := c.protoClient.UnregisterActorTimer(c.withAuthToken(ctx), req)
_, err := c.protoClient.UnregisterActorTimer(ctx, req)
if err != nil {
return fmt.Errorf("error invoking binding %s/%s: %w", in.ActorType, in.ActorID, err)
}
@ -328,7 +289,7 @@ func (c *GRPCClient) implActor(actor actor.Client, serializer codec.Codec) {
}
numField := valueOfActor.NumField()
for i := 0; i < numField; i++ {
for i := range numField {
t := typeOfActor.Field(i)
methodName := t.Name
if methodName == "Type" {
@ -351,7 +312,7 @@ func (c *GRPCClient) implActor(actor actor.Client, serializer codec.Codec) {
}
funcOuts := make([]reflect.Type, outNum)
for i := 0; i < outNum; i++ {
for i := range outNum {
funcOuts[i] = t.Type.Out(i)
}
@ -452,7 +413,7 @@ func (c *GRPCClient) GetActorState(ctx context.Context, in *GetActorStateRequest
if in.KeyName == "" {
return nil, errors.New("actor get state invocation keyName required")
}
rsp, err := c.protoClient.GetActorState(c.withAuthToken(ctx), &pb.GetActorStateRequest{
rsp, err := c.protoClient.GetActorState(ctx, &pb.GetActorStateRequest{
ActorId: in.ActorID,
ActorType: in.ActorType,
Key: in.KeyName,
@ -460,7 +421,7 @@ func (c *GRPCClient) GetActorState(ctx context.Context, in *GetActorStateRequest
if err != nil {
return nil, fmt.Errorf("error invoking actor get state %s/%s: %w", in.ActorType, in.ActorID, err)
}
return &GetActorStateResponse{Data: rsp.Data}, nil
return &GetActorStateResponse{Data: rsp.GetData()}, nil
}
type ActorStateOperation struct {
@ -496,7 +457,7 @@ func (c *GRPCClient) SaveStateTransactionally(ctx context.Context, actorType, ac
Metadata: metadata,
})
}
_, err := c.protoClient.ExecuteActorStateTransaction(c.withAuthToken(ctx), &pb.ExecuteActorStateTransactionRequest{
_, err := c.protoClient.ExecuteActorStateTransaction(ctx, &pb.ExecuteActorStateTransactionRequest{
ActorType: actorType,
ActorId: actorID,
Operations: grpcOperations,

View File

@ -14,16 +14,17 @@ limitations under the License.
package client
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
)
const testActorType = "test"
func TestInvokeActor(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
in := &InvokeActorRequest{
ActorID: "fn",
Method: "mockMethod",
@ -35,7 +36,7 @@ func TestInvokeActor(t *testing.T) {
in.Data = nil
out, err := testClient.InvokeActor(ctx, in)
in.Data = []byte(`{hello}`)
assert.NoError(t, err)
require.NoError(t, err)
assert.NotNil(t, out)
})
@ -43,7 +44,7 @@ func TestInvokeActor(t *testing.T) {
in.Method = ""
out, err := testClient.InvokeActor(ctx, in)
in.Method = "mockMethod"
assert.Error(t, err)
require.Error(t, err)
assert.Nil(t, out)
})
@ -51,7 +52,7 @@ func TestInvokeActor(t *testing.T) {
in.ActorID = ""
out, err := testClient.InvokeActor(ctx, in)
in.ActorID = "fn"
assert.Error(t, err)
require.Error(t, err)
assert.Nil(t, out)
})
@ -59,20 +60,20 @@ func TestInvokeActor(t *testing.T) {
in.ActorType = ""
out, err := testClient.InvokeActor(ctx, in)
in.ActorType = testActorType
assert.Error(t, err)
require.Error(t, err)
assert.Nil(t, out)
})
t.Run("invoke actor without empty input", func(t *testing.T) {
in = nil
out, err := testClient.InvokeActor(ctx, in)
assert.Error(t, err)
require.Error(t, err)
assert.Nil(t, out)
})
}
func TestRegisterActorReminder(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
in := &RegisterActorReminderRequest{
ActorID: "fn",
Data: []byte(`{hello}`),
@ -87,55 +88,55 @@ func TestRegisterActorReminder(t *testing.T) {
in.ActorType = ""
err := testClient.RegisterActorReminder(ctx, in)
in.ActorType = testActorType
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke register actor reminder without id ", func(t *testing.T) {
in.ActorID = ""
err := testClient.RegisterActorReminder(ctx, in)
in.ActorID = "fn"
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke register actor reminder without Name ", func(t *testing.T) {
in.Name = ""
err := testClient.RegisterActorReminder(ctx, in)
in.Name = "mockName"
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke register actor reminder without period ", func(t *testing.T) {
in.Period = ""
err := testClient.RegisterActorReminder(ctx, in)
in.Period = "2s"
assert.NoError(t, err)
require.NoError(t, err)
})
t.Run("invoke register actor reminder without dutTime ", func(t *testing.T) {
in.DueTime = ""
err := testClient.RegisterActorReminder(ctx, in)
in.DueTime = "2s"
assert.NoError(t, err)
require.NoError(t, err)
})
t.Run("invoke register actor reminder without TTL ", func(t *testing.T) {
in.TTL = ""
err := testClient.RegisterActorReminder(ctx, in)
in.TTL = "20s"
assert.NoError(t, err)
require.NoError(t, err)
})
t.Run("invoke register actor reminder ", func(t *testing.T) {
assert.NoError(t, testClient.RegisterActorReminder(ctx, in))
require.NoError(t, testClient.RegisterActorReminder(ctx, in))
})
t.Run("invoke register actor reminder with empty param", func(t *testing.T) {
assert.Error(t, testClient.RegisterActorReminder(ctx, nil))
require.Error(t, testClient.RegisterActorReminder(ctx, nil))
})
}
func TestRegisterActorTimer(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
in := &RegisterActorTimerRequest{
ActorID: "fn",
Data: []byte(`{hello}`),
@ -151,69 +152,69 @@ func TestRegisterActorTimer(t *testing.T) {
in.ActorType = ""
err := testClient.RegisterActorTimer(ctx, in)
in.ActorType = testActorType
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke register actor timer without id ", func(t *testing.T) {
in.ActorID = ""
err := testClient.RegisterActorTimer(ctx, in)
in.ActorID = "fn"
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke register actor timer without Name ", func(t *testing.T) {
in.Name = ""
err := testClient.RegisterActorTimer(ctx, in)
in.Name = "mockName"
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke register actor timer without period ", func(t *testing.T) {
in.Period = ""
err := testClient.RegisterActorTimer(ctx, in)
in.Period = "2s"
assert.NoError(t, err)
require.NoError(t, err)
})
t.Run("invoke register actor timer without dutTime ", func(t *testing.T) {
in.DueTime = ""
err := testClient.RegisterActorTimer(ctx, in)
in.DueTime = "4s"
assert.NoError(t, err)
require.NoError(t, err)
})
t.Run("invoke register actor timer without TTL ", func(t *testing.T) {
in.TTL = ""
err := testClient.RegisterActorTimer(ctx, in)
in.TTL = "20s"
assert.NoError(t, err)
require.NoError(t, err)
})
t.Run("invoke register actor timer without callBack ", func(t *testing.T) {
in.CallBack = ""
err := testClient.RegisterActorTimer(ctx, in)
in.CallBack = "mockFunc"
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke register actor timer without data ", func(t *testing.T) {
in.Data = nil
err := testClient.RegisterActorTimer(ctx, in)
in.Data = []byte(`{hello}`)
assert.NoError(t, err)
require.NoError(t, err)
})
t.Run("invoke register actor timer", func(t *testing.T) {
assert.NoError(t, testClient.RegisterActorTimer(ctx, in))
require.NoError(t, testClient.RegisterActorTimer(ctx, in))
})
t.Run("invoke register actor timer with empty param", func(t *testing.T) {
assert.Error(t, testClient.RegisterActorTimer(ctx, nil))
require.Error(t, testClient.RegisterActorTimer(ctx, nil))
})
}
func TestUnregisterActorReminder(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
in := &UnregisterActorReminderRequest{
ActorID: "fn",
ActorType: testActorType,
@ -224,100 +225,41 @@ func TestUnregisterActorReminder(t *testing.T) {
in.ActorType = ""
err := testClient.UnregisterActorReminder(ctx, in)
in.ActorType = testActorType
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke unregister actor reminder without id ", func(t *testing.T) {
in.ActorID = ""
err := testClient.UnregisterActorReminder(ctx, in)
in.ActorID = "fn"
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke unregister actor reminder without Name ", func(t *testing.T) {
in.Name = ""
err := testClient.UnregisterActorReminder(ctx, in)
in.Name = "mockName"
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke unregister actor reminder without period ", func(t *testing.T) {
in.ActorType = ""
err := testClient.UnregisterActorReminder(ctx, in)
in.ActorType = testActorType
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke unregister actor reminder ", func(t *testing.T) {
assert.NoError(t, testClient.UnregisterActorReminder(ctx, in))
require.NoError(t, testClient.UnregisterActorReminder(ctx, in))
})
t.Run("invoke unregister actor reminder with empty param", func(t *testing.T) {
assert.Error(t, testClient.UnregisterActorReminder(ctx, nil))
})
}
func TestRenameActorReminder(t *testing.T) {
ctx := context.Background()
registerReminderReq := &RegisterActorReminderRequest{
ActorID: "fn",
Data: []byte(`{hello}`),
ActorType: testActorType,
Name: "oldName",
Period: "2s",
DueTime: "4s",
TTL: "20s",
}
testClient.RegisterActorReminder(ctx, registerReminderReq)
renameReminderReq := &RenameActorReminderRequest{
ActorID: "fn",
ActorType: testActorType,
OldName: "oldName",
NewName: "newName",
}
t.Run("invoke rename actor reminder without actorType", func(t *testing.T) {
renameReminderReq.ActorType = ""
err := testClient.RenameActorReminder(ctx, renameReminderReq)
renameReminderReq.ActorType = testActorType
assert.Error(t, err)
})
t.Run("invoke rename actor reminder without id ", func(t *testing.T) {
renameReminderReq.ActorID = ""
err := testClient.RenameActorReminder(ctx, renameReminderReq)
renameReminderReq.ActorID = "fn"
assert.Error(t, err)
})
t.Run("invoke rename actor reminder without oldName ", func(t *testing.T) {
renameReminderReq.OldName = ""
err := testClient.RenameActorReminder(ctx, renameReminderReq)
renameReminderReq.OldName = "oldName"
assert.Error(t, err)
})
t.Run("invoke rename actor reminder without newName ", func(t *testing.T) {
renameReminderReq.NewName = ""
err := testClient.RenameActorReminder(ctx, renameReminderReq)
renameReminderReq.NewName = "newName"
assert.Error(t, err)
})
t.Run("invoke rename actor reminder ", func(t *testing.T) {
assert.NoError(t, testClient.RenameActorReminder(ctx, renameReminderReq))
})
t.Run("invoke rename actor reminder with empty param", func(t *testing.T) {
assert.Error(t, testClient.RenameActorReminder(ctx, nil))
require.Error(t, testClient.UnregisterActorReminder(ctx, nil))
})
}
func TestUnregisterActorTimer(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
in := &UnregisterActorTimerRequest{
ActorID: "fn",
ActorType: testActorType,
@ -328,35 +270,35 @@ func TestUnregisterActorTimer(t *testing.T) {
in.ActorType = ""
err := testClient.UnregisterActorTimer(ctx, in)
in.ActorType = testActorType
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke register actor timer without id ", func(t *testing.T) {
in.ActorID = ""
err := testClient.UnregisterActorTimer(ctx, in)
in.ActorID = "fn"
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke register actor timer without Name ", func(t *testing.T) {
in.Name = ""
err := testClient.UnregisterActorTimer(ctx, in)
in.Name = "mockName"
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke register actor timer without period ", func(t *testing.T) {
in.ActorType = ""
err := testClient.UnregisterActorTimer(ctx, in)
in.ActorType = testActorType
assert.Error(t, err)
require.Error(t, err)
})
t.Run("invoke register actor timer ", func(t *testing.T) {
assert.NoError(t, testClient.UnregisterActorTimer(ctx, in))
require.NoError(t, testClient.UnregisterActorTimer(ctx, in))
})
t.Run("invoke register actor timer with empty param", func(t *testing.T) {
assert.Error(t, testClient.UnregisterActorTimer(ctx, nil))
require.Error(t, testClient.UnregisterActorTimer(ctx, nil))
})
}

View File

@ -61,15 +61,15 @@ func (c *GRPCClient) InvokeBinding(ctx context.Context, in *InvokeBindingRequest
Metadata: in.Metadata,
}
resp, err := c.protoClient.InvokeBinding(c.withAuthToken(ctx), req)
resp, err := c.protoClient.InvokeBinding(ctx, req)
if err != nil {
return nil, fmt.Errorf("error invoking binding %s/%s: %w", in.Name, in.Operation, err)
}
if resp != nil {
return &BindingEvent{
Data: resp.Data,
Metadata: resp.Metadata,
Data: resp.GetData(),
Metadata: resp.GetMetadata(),
}, nil
}

View File

@ -14,16 +14,17 @@ limitations under the License.
package client
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
)
// go test -timeout 30s ./client -count 1 -run ^TestInvokeBinding$
func TestInvokeBinding(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
in := &InvokeBindingRequest{
Name: "test",
Operation: "fn",
@ -31,19 +32,19 @@ func TestInvokeBinding(t *testing.T) {
t.Run("output binding without data", func(t *testing.T) {
err := testClient.InvokeOutputBinding(ctx, in)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("output binding", func(t *testing.T) {
in.Data = []byte("test")
err := testClient.InvokeOutputBinding(ctx, in)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("binding without data", func(t *testing.T) {
in.Data = nil
out, err := testClient.InvokeBinding(ctx, in)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, out)
})
@ -51,7 +52,7 @@ func TestInvokeBinding(t *testing.T) {
in.Data = []byte("test")
in.Metadata = map[string]string{"k1": "v1", "k2": "v2"}
out, err := testClient.InvokeBinding(ctx, in)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, out)
assert.Equal(t, "test", string(out.Data))
})

View File

@ -15,6 +15,7 @@ package client
import (
"context"
"crypto/tls"
"errors"
"fmt"
"io"
@ -28,12 +29,13 @@ import (
"github.com/dapr/go-sdk/actor"
"github.com/dapr/go-sdk/actor/config"
"github.com/dapr/go-sdk/client/internal"
"github.com/dapr/go-sdk/version"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/types/known/emptypb"
pb "github.com/dapr/dapr/pkg/proto/runtime/v1"
@ -44,6 +46,7 @@ import (
const (
daprPortDefault = "50001"
daprPortEnvVarName = "DAPR_GRPC_PORT" /* #nosec */
daprGRPCEndpointEnvVarName = "DAPR_GRPC_ENDPOINT"
traceparentKey = "traceparent"
apiTokenKey = "dapr-api-token" /* #nosec */
apiTokenEnvVarName = "DAPR_API_TOKEN" /* #nosec */
@ -58,6 +61,18 @@ var (
defaultClient Client
)
// SetLogger sets the global logger for the Dapr client.
// The default logger has a destination of os.Stdout, SetLogger allows you to
// optionally specify a custom logger (with a custom destination).
// To disable client logging entirely, use a nil argument e.g.: client.SetLogger(nil)
func SetLogger(l *log.Logger) {
if l == nil {
l = log.New(io.Discard, "", 0)
}
logger = l
}
// Client is the interface for Dapr client implementation.
//
//nolint:interfacebloat
@ -142,9 +157,19 @@ type Client interface {
// SubscribeConfigurationItems can subscribe the change of configuration items by storeName and keys, and return subscription id
SubscribeConfigurationItems(ctx context.Context, storeName string, keys []string, handler ConfigurationHandleFunction, opts ...ConfigurationOpt) (string, error)
// UnsubscribeConfigurationItems stops the subscription with target store's and ID.
// Deprecated: Closing the `SubscribeConfigurationItems` stream (closing the given context) will unsubscribe the client and should be used in favor of `UnsubscribeConfigurationItems`.
// UnsubscribeConfigurationItems can stop the subscription with target store's and id
UnsubscribeConfigurationItems(ctx context.Context, storeName string, id string, opts ...ConfigurationOpt) error
// Subscribe subscribes to a pubsub topic and streams messages to the returned Subscription.
// Subscription must be closed after finishing with subscribing.
Subscribe(ctx context.Context, opts SubscriptionOptions) (*Subscription, error)
// SubscribeWithHandler subscribes to a pubsub topic and calls the given handler on topic events.
// The returned cancel function must be called after finishing with subscribing.
SubscribeWithHandler(ctx context.Context, opts SubscriptionOptions, handler SubscriptionHandleFunction) (func() error, error)
// DeleteBulkState deletes content for multiple keys from store.
DeleteBulkState(ctx context.Context, storeName string, keys []string, meta map[string]string) error
@ -192,9 +217,6 @@ type Client interface {
// UnregisterActorReminder unregisters an actor reminder.
UnregisterActorReminder(ctx context.Context, req *UnregisterActorReminderRequest) error
// RenameActorReminder rename an actor reminder.
RenameActorReminder(ctx context.Context, req *RenameActorReminderRequest) error
// InvokeActor calls a method on an actor.
InvokeActor(ctx context.Context, req *InvokeActorRequest) (*InvokeActorResponse, error)
@ -207,8 +229,57 @@ type Client interface {
// ImplActorClientStub is to impl user defined actor client stub
ImplActorClientStub(actorClientStub actor.Client, opt ...config.Option)
// StartWorkflowBeta1 starts a workflow.
// Deprecated: Please use the workflow client (github.com/dapr/go-sdk/workflow).
// These methods for managing workflows are no longer supported and will be removed in the 1.16 release.
StartWorkflowBeta1(ctx context.Context, req *StartWorkflowRequest) (*StartWorkflowResponse, error)
// GetWorkflowBeta1 gets a workflow.
// Deprecated: Please use the workflow client (github.com/dapr/go-sdk/workflow).
// These methods for managing workflows are no longer supported and will be removed in the 1.16 release.
GetWorkflowBeta1(ctx context.Context, req *GetWorkflowRequest) (*GetWorkflowResponse, error)
// PurgeWorkflowBeta1 purges a workflow.
// Deprecated: Please use the workflow client (github.com/dapr/go-sdk/workflow).
// These methods for managing workflows are no longer supported and will be removed in the 1.16 release.
PurgeWorkflowBeta1(ctx context.Context, req *PurgeWorkflowRequest) error
// TerminateWorkflowBeta1 terminates a workflow.
// Deprecated: Please use the workflow client (github.com/dapr/go-sdk/workflow).
// These methods for managing workflows are no longer supported and will be removed in the 1.16 release.
TerminateWorkflowBeta1(ctx context.Context, req *TerminateWorkflowRequest) error
// PauseWorkflowBeta1 pauses a workflow.
// Deprecated: Please use the workflow client (github.com/dapr/go-sdk/workflow).
// These methods for managing workflows are no longer supported and will be removed in the 1.16 release.
PauseWorkflowBeta1(ctx context.Context, req *PauseWorkflowRequest) error
// ResumeWorkflowBeta1 resumes a workflow.
// Deprecated: Please use the workflow client (github.com/dapr/go-sdk/workflow).
// These methods for managing workflows are no longer supported and will be removed in the 1.16 release.
ResumeWorkflowBeta1(ctx context.Context, req *ResumeWorkflowRequest) error
// RaiseEventWorkflowBeta1 raises an event for a workflow.
// Deprecated: Please use the workflow client (github.com/dapr/go-sdk/workflow).
// These methods for managing workflows are no longer supported and will be removed in the 1.16 release.
RaiseEventWorkflowBeta1(ctx context.Context, req *RaiseEventWorkflowRequest) error
// ScheduleJobAlpha1 creates and schedules a job.
ScheduleJobAlpha1(ctx context.Context, req *Job) error
// GetJobAlpha1 returns a scheduled job.
GetJobAlpha1(ctx context.Context, name string) (*Job, error)
// DeleteJobAlpha1 deletes a scheduled job.
DeleteJobAlpha1(ctx context.Context, name string) error
// ConverseAlpha1 interacts with a conversational AI model.
ConverseAlpha1(ctx context.Context, request conversationRequest, options ...conversationRequestOption) (*ConversationResponse, error)
// GrpcClient returns the base grpc client if grpc is used and nil otherwise
GrpcClient() pb.DaprClient
GrpcClientConn() *grpc.ClientConn
}
// NewClient instantiates Dapr client using DAPR_GRPC_PORT environment variable as port.
@ -221,18 +292,28 @@ type Client interface {
// NewClientWithConnection(conn *grpc.ClientConn) Client
// NewClientWithSocket(socket string) (client Client, err error)
func NewClient() (client Client, err error) {
port := os.Getenv(daprPortEnvVarName)
if port == "" {
port = daprPortDefault
}
if defaultClient != nil {
return defaultClient, nil
}
lock.Lock()
defer lock.Unlock()
if defaultClient != nil {
return defaultClient, nil
}
addr, ok := os.LookupEnv(daprGRPCEndpointEnvVarName)
if ok {
client, err = NewClientWithAddress(addr)
if err != nil {
return nil, fmt.Errorf("error creating %q client: %w", daprGRPCEndpointEnvVarName, err)
}
defaultClient = client
return defaultClient, nil
}
port, ok := os.LookupEnv(daprPortEnvVarName)
if !ok {
port = daprPortDefault
}
c, err := NewClientWithPort(port)
if err != nil {
return nil, fmt.Errorf("error creating default client: %w", err)
@ -268,23 +349,39 @@ func NewClientWithAddressContext(ctx context.Context, address string) (client Cl
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(ctx, time.Duration(timeoutSeconds)*time.Second)
conn, err := grpc.DialContext(
ctx,
address,
grpc.WithTransportCredentials(insecure.NewCredentials()),
parsedAddress, err := internal.ParseGRPCEndpoint(address)
if err != nil {
return nil, fmt.Errorf("error parsing address '%s': %w", address, err)
}
at := &authToken{}
opts := []grpc.DialOption{
grpc.WithUserAgent(userAgent()),
grpc.WithBlock(),
grpc.WithBlock(), //nolint:staticcheck
authTokenUnaryInterceptor(at),
authTokenStreamInterceptor(at),
}
if parsedAddress.TLS {
opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(new(tls.Config))))
} else {
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
}
ctx, cancel := context.WithTimeout(ctx, time.Duration(timeoutSeconds)*time.Second)
conn, err := grpc.DialContext( //nolint:staticcheck
ctx,
parsedAddress.Target,
opts...,
)
cancel()
if err != nil {
return nil, fmt.Errorf("error creating connection to '%s': %w", address, err)
}
if hasToken := os.Getenv(apiTokenEnvVarName); hasToken != "" {
logger.Println("client uses API token")
}
return NewClientWithConnection(conn), nil
return newClientWithConnection(conn, at), nil
}
func getClientTimeoutSeconds() (int, error) {
@ -307,36 +404,82 @@ func NewClientWithSocket(socket string) (client Client, err error) {
if socket == "" {
return nil, errors.New("nil socket")
}
at := &authToken{}
logger.Printf("dapr client initializing for: %s", socket)
addr := "unix://" + socket
conn, err := grpc.Dial(
conn, err := grpc.Dial( //nolint:staticcheck
addr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithUserAgent(userAgent()),
authTokenUnaryInterceptor(at),
authTokenStreamInterceptor(at),
)
if err != nil {
return nil, fmt.Errorf("error creating connection to '%s': %w", addr, err)
}
if hasToken := os.Getenv(apiTokenEnvVarName); hasToken != "" {
return newClientWithConnection(conn, at), nil
}
func newClientWithConnection(conn *grpc.ClientConn, authToken *authToken) Client {
apiToken := os.Getenv(apiTokenEnvVarName)
if apiToken != "" {
logger.Println("client uses API token")
authToken.set(apiToken)
}
return &GRPCClient{
connection: conn,
protoClient: pb.NewDaprClient(conn),
authToken: authToken,
}
return NewClientWithConnection(conn), nil
}
// NewClientWithConnection instantiates Dapr client using specific connection.
func NewClientWithConnection(conn *grpc.ClientConn) Client {
return &GRPCClient{
connection: conn,
protoClient: pb.NewDaprClient(conn),
authToken: os.Getenv(apiTokenEnvVarName),
}
return newClientWithConnection(conn, &authToken{})
}
type authToken struct {
mu sync.RWMutex
authToken string
}
func (a *authToken) get() string {
a.mu.RLock()
defer a.mu.RUnlock()
return a.authToken
}
func (a *authToken) set(token string) {
a.mu.Lock()
defer a.mu.Unlock()
a.authToken = token
}
func authTokenUnaryInterceptor(authToken *authToken) grpc.DialOption {
return grpc.WithUnaryInterceptor(func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
token := authToken.get()
if token != "" {
ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs(apiTokenKey, token))
}
return invoker(ctx, method, req, reply, cc, opts...)
})
}
func authTokenStreamInterceptor(authToken *authToken) grpc.DialOption {
return grpc.WithStreamInterceptor(func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
token := authToken.get()
if token != "" {
ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs(apiTokenKey, token))
}
return streamer(ctx, desc, cc, method, opts...)
})
}
// GRPCClient is the gRPC implementation of Dapr client.
type GRPCClient struct {
connection *grpc.ClientConn
protoClient pb.DaprClient
authToken string
authToken *authToken
}
// Close cleans up all resources created by the client.
@ -350,7 +493,7 @@ func (c *GRPCClient) Close() {
// WithAuthToken sets Dapr API token on the instantiated client.
// Allows empty string to reset token on existing client.
func (c *GRPCClient) WithAuthToken(token string) {
c.authToken = token
c.authToken.set(token)
}
// WithTraceID adds existing trace ID to the outgoing context.
@ -363,16 +506,9 @@ func (c *GRPCClient) WithTraceID(ctx context.Context, id string) context.Context
return metadata.NewOutgoingContext(ctx, md)
}
func (c *GRPCClient) withAuthToken(ctx context.Context) context.Context {
if c.authToken == "" {
return ctx
}
return metadata.NewOutgoingContext(ctx, metadata.Pairs(apiTokenKey, c.authToken))
}
// Shutdown the sidecar.
func (c *GRPCClient) Shutdown(ctx context.Context) error {
_, err := c.protoClient.Shutdown(c.withAuthToken(ctx), &emptypb.Empty{})
_, err := c.protoClient.Shutdown(ctx, &pb.ShutdownRequest{})
if err != nil {
return fmt.Errorf("error shutting down the sidecar: %w", err)
}

View File

@ -25,7 +25,6 @@ import (
"testing"
"time"
"github.com/golang/protobuf/ptypes/empty"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -33,14 +32,16 @@ import (
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/test/bufconn"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/emptypb"
commonv1pb "github.com/dapr/dapr/pkg/proto/common/v1"
pb "github.com/dapr/dapr/pkg/proto/runtime/v1"
)
const (
testBufSize = 1024 * 1024
testSocket = "/tmp/dapr.socket"
testBufSize = 1024 * 1024
testSocket = "/tmp/dapr.socket"
testWorkflowFailureID = "test_failure_id"
)
var testClient Client
@ -66,22 +67,22 @@ func TestMain(m *testing.M) {
func TestNewClient(t *testing.T) {
t.Run("return error when unable to reach server", func(t *testing.T) {
_, err := NewClientWithPort("1")
assert.Error(t, err)
require.Error(t, err)
})
t.Run("no arg for with port", func(t *testing.T) {
_, err := NewClientWithPort("")
assert.Error(t, err)
require.Error(t, err)
})
t.Run("no arg for with address", func(t *testing.T) {
_, err := NewClientWithAddress("")
assert.Error(t, err)
require.Error(t, err)
})
t.Run("no arg with socket", func(t *testing.T) {
_, err := NewClientWithSocket("")
assert.Error(t, err)
require.Error(t, err)
})
t.Run("new client closed with token", func(t *testing.T) {
@ -97,7 +98,7 @@ func TestNewClient(t *testing.T) {
})
t.Run("new client with trace ID", func(t *testing.T) {
_ = testClient.WithTraceID(context.Background(), "test")
_ = testClient.WithTraceID(t.Context(), "test")
})
t.Run("new socket client closed with token", func(t *testing.T) {
@ -119,17 +120,17 @@ func TestNewClient(t *testing.T) {
c, err := NewClientWithSocket(testSocket)
require.NoError(t, err)
defer c.Close()
ctx := c.WithTraceID(context.Background(), "")
ctx := c.WithTraceID(t.Context(), "")
_ = c.WithTraceID(ctx, "test")
})
}
func TestShutdown(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
t.Run("shutdown", func(t *testing.T) {
err := testClient.Shutdown(ctx)
assert.NoError(t, err)
require.NoError(t, err)
})
}
@ -150,7 +151,7 @@ func getTestClient(ctx context.Context) (client Client, closer func()) {
d := grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) {
return l.Dial()
})
//nolint:staticcheck
c, err := grpc.DialContext(ctx, "", d, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
logger.Fatalf("failed to dial test context: %v", err)
@ -201,33 +202,33 @@ func Test_getClientTimeoutSeconds(t *testing.T) {
t.Run("empty env var", func(t *testing.T) {
t.Setenv(clientTimeoutSecondsEnvVarName, "")
got, err := getClientTimeoutSeconds()
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, clientDefaultTimeoutSeconds, got)
})
t.Run("invalid env var", func(t *testing.T) {
t.Setenv(clientTimeoutSecondsEnvVarName, "invalid")
_, err := getClientTimeoutSeconds()
assert.Error(t, err)
require.Error(t, err)
})
t.Run("normal env var", func(t *testing.T) {
t.Setenv(clientTimeoutSecondsEnvVarName, "7")
got, err := getClientTimeoutSeconds()
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, 7, got)
})
t.Run("zero env var", func(t *testing.T) {
t.Setenv(clientTimeoutSecondsEnvVarName, "0")
_, err := getClientTimeoutSeconds()
assert.Error(t, err)
require.Error(t, err)
})
t.Run("negative env var", func(t *testing.T) {
t.Setenv(clientTimeoutSecondsEnvVarName, "-3")
_, err := getClientTimeoutSeconds()
assert.Error(t, err)
require.Error(t, err)
})
}
@ -251,7 +252,7 @@ func (s *testDaprServer) UnlockAlpha1(ctx context.Context, req *pb.UnlockRequest
}
func (s *testDaprServer) InvokeService(ctx context.Context, req *pb.InvokeServiceRequest) (*commonv1pb.InvokeResponse, error) {
if req.Message == nil {
if req.GetMessage() == nil {
return &commonv1pb.InvokeResponse{
ContentType: "text/plain",
Data: &anypb.Any{
@ -260,14 +261,14 @@ func (s *testDaprServer) InvokeService(ctx context.Context, req *pb.InvokeServic
}, nil
}
return &commonv1pb.InvokeResponse{
ContentType: req.Message.ContentType,
Data: req.Message.Data,
ContentType: req.GetMessage().GetContentType(),
Data: req.GetMessage().GetData(),
}, nil
}
func (s *testDaprServer) GetState(ctx context.Context, req *pb.GetStateRequest) (*pb.GetStateResponse, error) {
return &pb.GetStateResponse{
Data: s.state[req.Key],
Data: s.state[req.GetKey()],
Etag: "1",
}, nil
}
@ -289,16 +290,16 @@ func (s *testDaprServer) GetBulkState(ctx context.Context, in *pb.GetBulkStateRe
}, nil
}
func (s *testDaprServer) SaveState(ctx context.Context, req *pb.SaveStateRequest) (*empty.Empty, error) {
for _, item := range req.States {
s.state[item.Key] = item.Value
func (s *testDaprServer) SaveState(ctx context.Context, req *pb.SaveStateRequest) (*emptypb.Empty, error) {
for _, item := range req.GetStates() {
s.state[item.GetKey()] = item.GetValue()
}
return &empty.Empty{}, nil
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) QueryStateAlpha1(ctx context.Context, req *pb.QueryStateRequest) (*pb.QueryStateResponse, error) {
var v map[string]interface{}
if err := json.Unmarshal([]byte(req.Query), &v); err != nil {
if err := json.Unmarshal([]byte(req.GetQuery()), &v); err != nil {
return nil, err
}
@ -306,39 +307,39 @@ func (s *testDaprServer) QueryStateAlpha1(ctx context.Context, req *pb.QueryStat
Results: make([]*pb.QueryStateItem, 0, len(s.state)),
}
for key, value := range s.state {
ret.Results = append(ret.Results, &pb.QueryStateItem{Key: key, Data: value})
ret.Results = append(ret.GetResults(), &pb.QueryStateItem{Key: key, Data: value})
}
return ret, nil
}
func (s *testDaprServer) DeleteState(ctx context.Context, req *pb.DeleteStateRequest) (*empty.Empty, error) {
delete(s.state, req.Key)
return &empty.Empty{}, nil
func (s *testDaprServer) DeleteState(ctx context.Context, req *pb.DeleteStateRequest) (*emptypb.Empty, error) {
delete(s.state, req.GetKey())
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) DeleteBulkState(ctx context.Context, req *pb.DeleteBulkStateRequest) (*empty.Empty, error) {
for _, item := range req.States {
delete(s.state, item.Key)
func (s *testDaprServer) DeleteBulkState(ctx context.Context, req *pb.DeleteBulkStateRequest) (*emptypb.Empty, error) {
for _, item := range req.GetStates() {
delete(s.state, item.GetKey())
}
return &empty.Empty{}, nil
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) ExecuteStateTransaction(ctx context.Context, in *pb.ExecuteStateTransactionRequest) (*empty.Empty, error) {
func (s *testDaprServer) ExecuteStateTransaction(ctx context.Context, in *pb.ExecuteStateTransactionRequest) (*emptypb.Empty, error) {
for _, op := range in.GetOperations() {
item := op.GetRequest()
switch opType := op.GetOperationType(); opType {
case "upsert":
s.state[item.Key] = item.Value
s.state[item.GetKey()] = item.GetValue()
case "delete":
delete(s.state, item.Key)
delete(s.state, item.GetKey())
default:
return &empty.Empty{}, fmt.Errorf("invalid operation type: %s", opType)
return &emptypb.Empty{}, fmt.Errorf("invalid operation type: %s", opType)
}
}
return &empty.Empty{}, nil
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) GetMetadata(ctx context.Context, req *empty.Empty) (metadata *pb.GetMetadataResponse, err error) {
func (s *testDaprServer) GetMetadata(ctx context.Context, req *pb.GetMetadataRequest) (metadata *pb.GetMetadataResponse, err error) {
resp := &pb.GetMetadataResponse{
Id: uuid.NewString(),
ActiveActorsCount: []*pb.ActiveActorsCount{},
@ -349,12 +350,12 @@ func (s *testDaprServer) GetMetadata(ctx context.Context, req *empty.Empty) (met
return resp, nil
}
func (s *testDaprServer) SetMetadata(ctx context.Context, req *pb.SetMetadataRequest) (*empty.Empty, error) {
return &empty.Empty{}, nil
func (s *testDaprServer) SetMetadata(ctx context.Context, req *pb.SetMetadataRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) PublishEvent(ctx context.Context, req *pb.PublishEventRequest) (*empty.Empty, error) {
return &empty.Empty{}, nil
func (s *testDaprServer) PublishEvent(ctx context.Context, req *pb.PublishEventRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, nil
}
// BulkPublishEventAlpha1 mocks the BulkPublishEventAlpha1 API.
@ -362,14 +363,14 @@ func (s *testDaprServer) PublishEvent(ctx context.Context, req *pb.PublishEventR
// It will fail the entire request if an event starts with "failall".
func (s *testDaprServer) BulkPublishEventAlpha1(ctx context.Context, req *pb.BulkPublishRequest) (*pb.BulkPublishResponse, error) {
failedEntries := make([]*pb.BulkPublishResponseFailedEntry, 0)
for _, entry := range req.Entries {
if bytes.HasPrefix(entry.Event, []byte("failall")) {
for _, entry := range req.GetEntries() {
if bytes.HasPrefix(entry.GetEvent(), []byte("failall")) {
// fail the entire request
return nil, errors.New("failed to publish events")
} else if bytes.HasPrefix(entry.Event, []byte("fail")) {
} else if bytes.HasPrefix(entry.GetEvent(), []byte("fail")) {
// fail this entry
failedEntries = append(failedEntries, &pb.BulkPublishResponseFailedEntry{
EntryId: entry.EntryId,
EntryId: entry.GetEntryId(),
Error: "failed to publish events",
})
}
@ -378,15 +379,15 @@ func (s *testDaprServer) BulkPublishEventAlpha1(ctx context.Context, req *pb.Bul
}
func (s *testDaprServer) InvokeBinding(ctx context.Context, req *pb.InvokeBindingRequest) (*pb.InvokeBindingResponse, error) {
if req.Data == nil {
if req.GetData() == nil {
return &pb.InvokeBindingResponse{
Data: []byte("test"),
Metadata: map[string]string{"k1": "v1", "k2": "v2"},
}, nil
}
return &pb.InvokeBindingResponse{
Data: req.Data,
Metadata: req.Metadata,
Data: req.GetData(),
Metadata: req.GetMetadata(),
}, nil
}
@ -410,16 +411,12 @@ func (s *testDaprServer) GetBulkSecret(ctx context.Context, req *pb.GetBulkSecre
}, nil
}
func (s *testDaprServer) RegisterActorReminder(ctx context.Context, req *pb.RegisterActorReminderRequest) (*empty.Empty, error) {
return &empty.Empty{}, nil
func (s *testDaprServer) RegisterActorReminder(ctx context.Context, req *pb.RegisterActorReminderRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) UnregisterActorReminder(ctx context.Context, req *pb.UnregisterActorReminderRequest) (*empty.Empty, error) {
return &empty.Empty{}, nil
}
func (s *testDaprServer) RenameActorReminder(ctx context.Context, req *pb.RenameActorReminderRequest) (*empty.Empty, error) {
return &empty.Empty{}, nil
func (s *testDaprServer) UnregisterActorReminder(ctx context.Context, req *pb.UnregisterActorReminderRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) InvokeActor(context.Context, *pb.InvokeActorRequest) (*pb.InvokeActorResponse, error) {
@ -428,16 +425,16 @@ func (s *testDaprServer) InvokeActor(context.Context, *pb.InvokeActorRequest) (*
}, nil
}
func (s *testDaprServer) RegisterActorTimer(context.Context, *pb.RegisterActorTimerRequest) (*empty.Empty, error) {
return &empty.Empty{}, nil
func (s *testDaprServer) RegisterActorTimer(context.Context, *pb.RegisterActorTimerRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) UnregisterActorTimer(context.Context, *pb.UnregisterActorTimerRequest) (*empty.Empty, error) {
return &empty.Empty{}, nil
func (s *testDaprServer) UnregisterActorTimer(context.Context, *pb.UnregisterActorTimerRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) Shutdown(ctx context.Context, req *empty.Empty) (*empty.Empty, error) {
return &empty.Empty{}, nil
func (s *testDaprServer) Shutdown(ctx context.Context, req *pb.ShutdownRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) GetConfiguration(ctx context.Context, in *pb.GetConfigurationRequest) (*pb.GetConfigurationResponse, error) {
@ -469,7 +466,7 @@ func (s *testDaprServer) SubscribeConfiguration(in *pb.SubscribeConfigurationReq
return err
}
for i := 0; i < 5; i++ {
for range 5 {
select {
case <-stopCh:
return nil
@ -495,15 +492,98 @@ func (s *testDaprServer) SubscribeConfiguration(in *pb.SubscribeConfigurationReq
func (s *testDaprServer) UnsubscribeConfiguration(ctx context.Context, in *pb.UnsubscribeConfigurationRequest) (*pb.UnsubscribeConfigurationResponse, error) {
s.configurationSubscriptionIDMapLoc.Lock()
defer s.configurationSubscriptionIDMapLoc.Unlock()
ch, ok := s.configurationSubscriptionID[in.Id]
ch, ok := s.configurationSubscriptionID[in.GetId()]
if !ok {
return &pb.UnsubscribeConfigurationResponse{Ok: true}, nil
}
close(ch)
delete(s.configurationSubscriptionID, in.Id)
delete(s.configurationSubscriptionID, in.GetId())
return &pb.UnsubscribeConfigurationResponse{Ok: true}, nil
}
func (s *testDaprServer) StartWorkflowBeta1(ctx context.Context, in *pb.StartWorkflowRequest) (*pb.StartWorkflowResponse, error) {
if in.GetInstanceId() == testWorkflowFailureID {
return nil, errors.New("test failure")
}
return &pb.StartWorkflowResponse{
InstanceId: in.GetInstanceId(),
}, nil
}
func (s *testDaprServer) GetWorkflowBeta1(ctx context.Context, in *pb.GetWorkflowRequest) (*pb.GetWorkflowResponse, error) {
if in.GetInstanceId() == testWorkflowFailureID {
return nil, errors.New("test failure")
}
return &pb.GetWorkflowResponse{
InstanceId: in.GetInstanceId(),
WorkflowName: "TestWorkflowName",
RuntimeStatus: "Running",
Properties: make(map[string]string),
}, nil
}
func (s *testDaprServer) PurgeWorkflowBeta1(ctx context.Context, in *pb.PurgeWorkflowRequest) (*emptypb.Empty, error) {
if in.GetInstanceId() == testWorkflowFailureID {
return nil, errors.New("test failure")
}
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) TerminateWorkflowBeta1(ctx context.Context, in *pb.TerminateWorkflowRequest) (*emptypb.Empty, error) {
if in.GetInstanceId() == testWorkflowFailureID {
return nil, errors.New("test failure")
}
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) PauseWorkflowBeta1(ctx context.Context, in *pb.PauseWorkflowRequest) (*emptypb.Empty, error) {
if in.GetInstanceId() == testWorkflowFailureID {
return nil, errors.New("test failure")
}
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) ResumeWorkflowBeta1(ctx context.Context, in *pb.ResumeWorkflowRequest) (*emptypb.Empty, error) {
if in.GetInstanceId() == testWorkflowFailureID {
return nil, errors.New("test failure")
}
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) RaiseEventWorkflowBeta1(ctx context.Context, in *pb.RaiseEventWorkflowRequest) (*emptypb.Empty, error) {
if in.GetInstanceId() == testWorkflowFailureID {
return nil, errors.New("test failure")
}
return &emptypb.Empty{}, nil
}
func (s *testDaprServer) ScheduleJobAlpha1(ctx context.Context, in *pb.ScheduleJobRequest) (*pb.ScheduleJobResponse, error) {
return &pb.ScheduleJobResponse{}, nil
}
func (s *testDaprServer) GetJobAlpha1(ctx context.Context, in *pb.GetJobRequest) (*pb.GetJobResponse, error) {
var (
schedule = "@every 10s"
dueTime = "10s"
repeats uint32 = 4
ttl = "10s"
)
return &pb.GetJobResponse{
Job: &pb.Job{
Name: "name",
Schedule: &schedule,
Repeats: &repeats,
DueTime: &dueTime,
Ttl: &ttl,
Data: nil,
},
}, nil
}
func (s *testDaprServer) DeleteJobAlpha1(ctx context.Context, in *pb.DeleteJobRequest) (*pb.DeleteJobResponse, error) {
return &pb.DeleteJobResponse{}, nil
}
func TestGrpcClient(t *testing.T) {
protoClient := pb.NewDaprClient(nil)
client := &GRPCClient{protoClient: protoClient}

View File

@ -50,11 +50,11 @@ func (c *GRPCClient) GetConfigurationItems(ctx context.Context, storeName string
}
configItems := make(map[string]*ConfigurationItem)
for k, v := range rsp.Items {
for k, v := range rsp.GetItems() {
configItems[k] = &ConfigurationItem{
Value: v.Value,
Version: v.Version,
Metadata: v.Metadata,
Value: v.GetValue(),
Version: v.GetVersion(),
Metadata: v.GetMetadata(),
}
}
return configItems, nil
@ -88,21 +88,21 @@ func (c *GRPCClient) SubscribeConfigurationItems(ctx context.Context, storeName
}
configurationItems := make(map[string]*ConfigurationItem)
for k, v := range rsp.Items {
for k, v := range rsp.GetItems() {
configurationItems[k] = &ConfigurationItem{
Value: v.Value,
Version: v.Version,
Metadata: v.Metadata,
Value: v.GetValue(),
Version: v.GetVersion(),
Metadata: v.GetMetadata(),
}
}
// Get the subscription ID from the first response.
if isFirst {
subscribeIDChan <- rsp.Id
subscribeIDChan <- rsp.GetId()
isFirst = false
}
// Do not invoke handler in case there are no items.
if len(configurationItems) > 0 {
handler(rsp.Id, configurationItems)
handler(rsp.GetId(), configurationItems)
}
}
}()
@ -119,7 +119,7 @@ func (c *GRPCClient) UnsubscribeConfigurationItems(ctx context.Context, storeNam
if err != nil {
return fmt.Errorf("unsubscribe failed with error = %w", err)
}
if !resp.Ok {
if !resp.GetOk() {
return fmt.Errorf("unsubscribe error message = %s", resp.GetMessage())
}
return nil

View File

@ -1,11 +1,12 @@
package client
import (
"context"
"sync/atomic"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
)
@ -14,27 +15,27 @@ const (
)
func TestGetConfigurationItem(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
t.Run("get configuration item", func(t *testing.T) {
resp, err := testClient.GetConfigurationItem(ctx, "example-config", "mykey")
assert.Nil(t, err)
require.NoError(t, err)
assert.Equal(t, "mykey"+valueSuffix, resp.Value)
})
t.Run("get configuration item with invalid storeName", func(t *testing.T) {
_, err := testClient.GetConfigurationItem(ctx, "", "mykey")
assert.NotNil(t, err)
require.Error(t, err)
})
}
func TestGetConfigurationItems(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
keys := []string{"mykey1", "mykey2", "mykey3"}
t.Run("Test get configuration items", func(t *testing.T) {
resp, err := testClient.GetConfigurationItems(ctx, "example-config", keys)
assert.Nil(t, err)
require.NoError(t, err)
for _, k := range keys {
assert.Equal(t, k+valueSuffix, resp[k].Value)
}
@ -42,7 +43,7 @@ func TestGetConfigurationItems(t *testing.T) {
}
func TestSubscribeConfigurationItems(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
var counter, totalCounter uint32
counter = 0
@ -57,7 +58,7 @@ func TestSubscribeConfigurationItems(t *testing.T) {
atomic.AddUint32(&totalCounter, 1)
}
})
assert.Nil(t, err)
require.NoError(t, err)
})
time.Sleep(time.Second*5 + time.Millisecond*500)
assert.Equal(t, uint32(5), atomic.LoadUint32(&counter))
@ -65,7 +66,7 @@ func TestSubscribeConfigurationItems(t *testing.T) {
}
func TestUnSubscribeConfigurationItems(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
var counter, totalCounter uint32
t.Run("Test unsubscribe configuration items", func(t *testing.T) {
@ -78,11 +79,11 @@ func TestUnSubscribeConfigurationItems(t *testing.T) {
atomic.AddUint32(&totalCounter, 1)
}
})
assert.Nil(t, err)
require.NoError(t, err)
time.Sleep(time.Second * 2)
time.Sleep(time.Millisecond * 500)
err = testClient.UnsubscribeConfigurationItems(ctx, "example-config", subscribeID)
assert.Nil(t, err)
require.NoError(t, err)
})
time.Sleep(time.Second * 5)
assert.Equal(t, uint32(3), atomic.LoadUint32(&counter))

146
client/conversation.go Normal file
View File

@ -0,0 +1,146 @@
/*
Copyright 2024 The Dapr Authors
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 client
import (
"context"
"google.golang.org/protobuf/types/known/anypb"
runtimev1pb "github.com/dapr/dapr/pkg/proto/runtime/v1"
)
// conversationRequest object - currently unexported as used in a functions option pattern
type conversationRequest struct {
name string
inputs []ConversationInput
Parameters map[string]*anypb.Any
Metadata map[string]string
ContextID *string
ScrubPII *bool // Scrub PII from the output
Temperature *float64
}
// NewConversationRequest defines a request with a component name and one or more inputs as a slice
func NewConversationRequest(llmName string, inputs []ConversationInput) conversationRequest {
return conversationRequest{
name: llmName,
inputs: inputs,
}
}
type conversationRequestOption func(request *conversationRequest)
// ConversationInput defines a single input.
type ConversationInput struct {
// The content to send to the llm.
Content string
// The role of the message.
Role *string
// Whether to Scrub PII from the input
ScrubPII *bool
}
// ConversationResponse is the basic response from a conversationRequest.
type ConversationResponse struct {
ContextID string
Outputs []ConversationResult
}
// ConversationResult is the individual
type ConversationResult struct {
Result string
Parameters map[string]*anypb.Any
}
// WithParameters should be used to provide parameters for custom fields.
func WithParameters(parameters map[string]*anypb.Any) conversationRequestOption {
return func(o *conversationRequest) {
o.Parameters = parameters
}
}
// WithMetadata used to define metadata to be passed to components.
func WithMetadata(metadata map[string]string) conversationRequestOption {
return func(o *conversationRequest) {
o.Metadata = metadata
}
}
// WithContextID to provide a new context or continue an existing one.
func WithContextID(id string) conversationRequestOption {
return func(o *conversationRequest) {
o.ContextID = &id
}
}
// WithScrubPII to define whether the outputs should have PII removed.
func WithScrubPII(scrub bool) conversationRequestOption {
return func(o *conversationRequest) {
o.ScrubPII = &scrub
}
}
// WithTemperature to specify which way the LLM leans.
func WithTemperature(temp float64) conversationRequestOption {
return func(o *conversationRequest) {
o.Temperature = &temp
}
}
// ConverseAlpha1 can invoke an LLM given a request created by the NewConversationRequest function.
func (c *GRPCClient) ConverseAlpha1(ctx context.Context, req conversationRequest, options ...conversationRequestOption) (*ConversationResponse, error) {
cinputs := make([]*runtimev1pb.ConversationInput, len(req.inputs))
for i, in := range req.inputs {
cinputs[i] = &runtimev1pb.ConversationInput{
Content: in.Content,
Role: in.Role,
ScrubPII: in.ScrubPII,
}
}
for _, opt := range options {
if opt != nil {
opt(&req)
}
}
request := runtimev1pb.ConversationRequest{
Name: req.name,
ContextID: req.ContextID,
Inputs: cinputs,
Parameters: req.Parameters,
Metadata: req.Metadata,
ScrubPII: req.ScrubPII,
Temperature: req.Temperature,
}
resp, err := c.protoClient.ConverseAlpha1(ctx, &request)
if err != nil {
return nil, err
}
outputs := make([]ConversationResult, len(resp.GetOutputs()))
for i, o := range resp.GetOutputs() {
outputs[i] = ConversationResult{
Result: o.GetResult(),
Parameters: o.GetParameters(),
}
}
return &ConversationResponse{
ContextID: resp.GetContextID(),
Outputs: outputs,
}, nil
}

View File

@ -186,13 +186,13 @@ func (c *GRPCClient) performCryptoOperation(ctx context.Context, stream grpc.Cli
// Write the data, if any, into the pipe
payload = resProto.GetPayload()
if payload != nil {
if payload.Seq != expectSeq {
pw.CloseWithError(fmt.Errorf("invalid sequence number in chunk: %d (expected: %d)", payload.Seq, expectSeq))
if payload.GetSeq() != expectSeq {
pw.CloseWithError(fmt.Errorf("invalid sequence number in chunk: %d (expected: %d)", payload.GetSeq(), expectSeq))
return
}
expectSeq++
_, readErr = pw.Write(payload.Data)
_, readErr = pw.Write(payload.GetData())
if readErr != nil {
pw.CloseWithError(fmt.Errorf("error writing data: %w", readErr))
return

View File

@ -30,7 +30,7 @@ import (
)
func TestEncrypt(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
t.Run("missing ComponentName", func(t *testing.T) {
out, err := testClient.Encrypt(ctx,
@ -138,7 +138,7 @@ func TestEncrypt(t *testing.T) {
}
func TestDecrypt(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
t.Run("missing ComponentName", func(t *testing.T) {
out, err := testClient.Decrypt(ctx,
@ -236,13 +236,13 @@ func (s *testDaprServer) performCryptoOperation(stream grpc.ServerStream, reqPro
payload := reqProto.GetPayload()
if payload != nil {
if payload.Seq != expectSeq {
pw.CloseWithError(fmt.Errorf("invalid sequence number: %d (expected: %d)", payload.Seq, expectSeq))
if payload.GetSeq() != expectSeq {
pw.CloseWithError(fmt.Errorf("invalid sequence number: %d (expected: %d)", payload.GetSeq(), expectSeq))
return
}
expectSeq++
_, err = pw.Write(payload.Data)
_, err = pw.Write(payload.GetData())
if err != nil {
pw.CloseWithError(err)
return

174
client/internal/parse.go Normal file
View File

@ -0,0 +1,174 @@
/*
Copyright 2023 The Dapr Authors
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 internal
import (
"errors"
"fmt"
"net"
"net/url"
"strings"
)
// Parsed represents a parsed gRPC endpoint.
type Parsed struct {
Target string
TLS bool
}
func ParseGRPCEndpoint(endpoint string) (Parsed, error) {
target := endpoint
if len(target) == 0 {
return Parsed{}, errors.New("target is required")
}
var dnsAuthority string
var hostname string
var tls bool
urlSplit := strings.Split(target, ":")
if len(urlSplit) == 3 && !strings.Contains(target, "://") {
target = strings.Replace(target, ":", "://", 1)
} else if len(urlSplit) >= 2 && !strings.Contains(target, "://") && schemeKnown(urlSplit[0]) {
target = strings.Replace(target, ":", "://", 1)
} else {
urlSplit = strings.Split(target, "://")
if len(urlSplit) == 1 {
target = "dns://" + target
} else {
scheme := urlSplit[0]
if !schemeKnown(scheme) {
return Parsed{}, fmt.Errorf(("unknown scheme: %q"), scheme)
}
if scheme == "dns" {
urlSplit = strings.Split(target, "/")
if len(urlSplit) < 4 {
return Parsed{}, fmt.Errorf("invalid dns scheme: %q", target)
}
dnsAuthority = urlSplit[2]
target = "dns://" + urlSplit[3]
}
}
}
ptarget, err := url.Parse(target)
if err != nil {
return Parsed{}, err
}
var errs []string
for k := range ptarget.Query() {
if k != "tls" {
errs = append(errs, fmt.Sprintf("unrecognized query parameter: %q", k))
}
}
if len(errs) > 0 {
return Parsed{}, fmt.Errorf("failed to parse target %q: %s", target, strings.Join(errs, "; "))
}
if ptarget.Query().Has("tls") {
if ptarget.Scheme == "http" || ptarget.Scheme == "https" {
return Parsed{}, errors.New("cannot use tls query parameter with http(s) scheme")
}
qtls := ptarget.Query().Get("tls")
if qtls != "true" && qtls != "false" {
return Parsed{}, fmt.Errorf("invalid value for tls query parameter: %q", qtls)
}
tls = qtls == "true"
}
scheme := ptarget.Scheme
if scheme == "https" {
tls = true
}
if scheme == "http" || scheme == "https" {
scheme = "dns"
}
hostname = ptarget.Host
host, port, err := net.SplitHostPort(hostname)
aerr, ok := err.(*net.AddrError)
if ok && aerr.Err == "missing port in address" {
port = "443"
} else if err != nil {
return Parsed{}, err
} else {
hostname = host
}
if len(hostname) == 0 {
if scheme == "dns" {
hostname = "localhost"
} else {
hostname = ptarget.Path
}
}
switch scheme {
case "unix":
separator := ":"
if strings.HasPrefix(endpoint, "unix://") {
separator = "://"
}
target = scheme + separator + hostname
case "vsock":
target = scheme + ":" + hostname + ":" + port
case "unix-abstract":
target = scheme + ":" + hostname
case "dns":
if len(ptarget.Path) > 0 {
return Parsed{}, fmt.Errorf("path is not allowed: %q", ptarget.Path)
}
if strings.Count(hostname, ":") == 7 && !strings.HasPrefix(hostname, "[") && !strings.HasSuffix(hostname, "]") {
hostname = "[" + hostname + "]"
}
if len(dnsAuthority) > 0 {
dnsAuthority = "//" + dnsAuthority + "/"
}
target = scheme + ":" + dnsAuthority + hostname + ":" + port
default:
return Parsed{}, fmt.Errorf("unsupported scheme: %q", scheme)
}
return Parsed{
Target: target,
TLS: tls,
}, nil
}
func schemeKnown(scheme string) bool {
for _, s := range []string{
"dns",
"unix",
"unix-abstract",
"vsock",
"http",
"https",
} {
if scheme == s {
return true
}
}
return false
}

View File

@ -0,0 +1,293 @@
/*
Copyright 2023 The Dapr Authors
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 internal
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestParse(t *testing.T) {
tests := map[string]struct {
expTarget string
expTLS bool
expError bool
}{
"": {
expTarget: "",
expTLS: false,
expError: true,
},
":5000": {
expTarget: "dns:localhost:5000",
expTLS: false,
expError: false,
},
":5000?tls=false": {
expTarget: "dns:localhost:5000",
expTLS: false,
expError: false,
},
":5000?tls=true": {
expTarget: "dns:localhost:5000",
expTLS: true,
expError: false,
},
"myhost": {
expTarget: "dns:myhost:443",
expTLS: false,
expError: false,
},
"myhost?tls=false": {
expTarget: "dns:myhost:443",
expTLS: false,
expError: false,
},
"myhost?tls=true": {
expTarget: "dns:myhost:443",
expTLS: true,
expError: false,
},
"myhost:443": {
expTarget: "dns:myhost:443",
expTLS: false,
expError: false,
},
"myhost:443?tls=false": {
expTarget: "dns:myhost:443",
expTLS: false,
expError: false,
},
"myhost:443?tls=true": {
expTarget: "dns:myhost:443",
expTLS: true,
expError: false,
},
"http://myhost": {
expTarget: "dns:myhost:443",
expTLS: false,
expError: false,
},
"http://myhost?tls=false": {
expTarget: "",
expTLS: false,
expError: true,
},
"http://myhost?tls=true": {
expTarget: "",
expTLS: false,
expError: true,
},
"http://myhost:443": {
expTarget: "dns:myhost:443",
expTLS: false,
expError: false,
},
"http://myhost:443?tls=false": {
expTarget: "",
expTLS: false,
expError: true,
},
"http://myhost:443?tls=true": {
expTarget: "",
expTLS: false,
expError: true,
},
"http://myhost:5000": {
expTarget: "dns:myhost:5000",
expTLS: false,
expError: false,
},
"http://myhost:5000?tls=false": {
expTarget: "",
expTLS: false,
expError: true,
},
"http://myhost:5000?tls=true": {
expTarget: "",
expTLS: false,
expError: true,
},
"https://myhost:443": {
expTarget: "dns:myhost:443",
expTLS: true,
expError: false,
},
"https://myhost:443/tls=false": {
expTarget: "",
expTLS: false,
expError: true,
},
"https://myhost:443?tls=true": {
expTarget: "",
expTLS: false,
expError: true,
},
"dns:myhost": {
expTarget: "dns:myhost:443",
expTLS: false,
expError: false,
},
"dns:myhost?tls=false": {
expTarget: "dns:myhost:443",
expTLS: false,
expError: false,
},
"dns:myhost?tls=true": {
expTarget: "dns:myhost:443",
expTLS: true,
expError: false,
},
"dns://myauthority:53/myhost": {
expTarget: "dns://myauthority:53/myhost:443",
expTLS: false,
expError: false,
},
"dns://myauthority:53/myhost?tls=false": {
expTarget: "dns://myauthority:53/myhost:443",
expTLS: false,
expError: false,
},
"dns://myauthority:53/myhost?tls=true": {
expTarget: "dns://myauthority:53/myhost:443",
expTLS: true,
expError: false,
},
"dns://myhost": {
expTarget: "",
expTLS: false,
expError: true,
},
"unix:my.sock": {
expTarget: "unix:my.sock",
expTLS: false,
expError: false,
},
"unix:my.sock?tls=true": {
expTarget: "unix:my.sock",
expTLS: true,
expError: false,
},
"unix://my.sock": {
expTarget: "unix://my.sock",
expTLS: false,
expError: false,
},
"unix:///my.sock": {
expTarget: "unix:///my.sock",
expTLS: false,
expError: false,
},
"unix://my.sock?tls=true": {
expTarget: "unix://my.sock",
expTLS: true,
expError: false,
},
"unix-abstract:my.sock": {
expTarget: "unix-abstract:my.sock",
expTLS: false,
expError: false,
},
"unix-abstract:my.sock?tls=false": {
expTarget: "unix-abstract:my.sock",
expTLS: false,
expError: false,
},
"unix-abstract:my.sock?tls=true": {
expTarget: "unix-abstract:my.sock",
expTLS: true,
expError: false,
},
"vsock:mycid:5000": {
expTarget: "vsock:mycid:5000",
expTLS: false,
expError: false,
},
"vsock:mycid:5000?tls=false": {
expTarget: "vsock:mycid:5000",
expTLS: false,
expError: false,
},
"vsock:mycid:5000?tls=true": {
expTarget: "vsock:mycid:5000",
expTLS: true,
expError: false,
},
"dns:1.2.3.4:443": {
expTarget: "dns:1.2.3.4:443",
expTLS: false,
expError: false,
},
"dns:[2001:db8:1f70::999:de8:7648:6e8]:443": {
expTarget: "dns:[2001:db8:1f70::999:de8:7648:6e8]:443",
expTLS: false,
expError: false,
},
"dns:[2001:db8:1f70::999:de8:7648:6e8]:5000": {
expTarget: "dns:[2001:db8:1f70::999:de8:7648:6e8]:5000",
expTLS: false,
expError: false,
},
"dns:[2001:db8:1f70::999:de8:7648:6e8]:5000?abc=[]": {
expTarget: "",
expTLS: false,
expError: true,
},
"dns://myauthority:53/[2001:db8:1f70::999:de8:7648:6e8]": {
expTarget: "dns://myauthority:53/[2001:db8:1f70::999:de8:7648:6e8]:443",
expTLS: false,
expError: false,
},
"https://[2001:db8:1f70::999:de8:7648:6e8]": {
expTarget: "dns:[2001:db8:1f70::999:de8:7648:6e8]:443",
expTLS: true,
expError: false,
},
"https://[2001:db8:1f70::999:de8:7648:6e8]:5000": {
expTarget: "dns:[2001:db8:1f70::999:de8:7648:6e8]:5000",
expTLS: true,
expError: false,
},
"host:5000/v1/dapr": {
expTarget: "",
expTLS: false,
expError: true,
},
"host:5000/?a=1": {
expTarget: "",
expTLS: false,
expError: true,
},
"inv-scheme://myhost": {
expTarget: "",
expTLS: false,
expError: true,
},
"inv-scheme:myhost:5000": {
expTarget: "",
expTLS: false,
expError: true,
},
}
for url, tc := range tests {
t.Run(url, func(t *testing.T) {
parsed, err := ParseGRPCEndpoint(url)
assert.Equalf(t, tc.expError, err != nil, "%v", err)
assert.Equal(t, tc.expTarget, parsed.Target)
assert.Equal(t, tc.expTLS, parsed.TLS)
})
}
}

View File

@ -20,7 +20,7 @@ import (
"fmt"
"strings"
anypb "github.com/golang/protobuf/ptypes/any"
"google.golang.org/protobuf/types/known/anypb"
v1 "github.com/dapr/dapr/pkg/proto/common/v1"
pb "github.com/dapr/dapr/pkg/proto/runtime/v1"
@ -39,14 +39,14 @@ func (c *GRPCClient) invokeServiceWithRequest(ctx context.Context, req *pb.Invok
return nil, errors.New("nil request")
}
resp, err := c.protoClient.InvokeService(c.withAuthToken(ctx), req)
resp, err := c.protoClient.InvokeService(ctx, req)
if err != nil {
return nil, err
}
// allow for service to not return any value
if resp != nil && resp.GetData() != nil {
out = resp.GetData().Value
out = resp.GetData().GetValue()
return
}

View File

@ -14,9 +14,10 @@ limitations under the License.
package client
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
v1 "github.com/dapr/dapr/pkg/proto/common/v1"
@ -37,7 +38,7 @@ type _testStructwithSlices struct {
}
func TestInvokeMethodWithContent(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
data := "ping"
t.Run("with content", func(t *testing.T) {
@ -46,7 +47,7 @@ func TestInvokeMethodWithContent(t *testing.T) {
Data: []byte(data),
}
resp, err := testClient.InvokeMethodWithContent(ctx, "test", "fn", "post", content)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, resp)
assert.Equal(t, string(resp), data)
})
@ -57,28 +58,28 @@ func TestInvokeMethodWithContent(t *testing.T) {
Data: []byte(data),
}
resp, err := testClient.InvokeMethodWithContent(ctx, "test", "fn?foo=bar&url=http://dapr.io", "get", content)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, resp)
assert.Equal(t, string(resp), data)
})
t.Run("without content", func(t *testing.T) {
resp, err := testClient.InvokeMethod(ctx, "test", "fn", "get")
assert.Nil(t, err)
require.NoError(t, err)
assert.Nil(t, resp)
})
t.Run("without service ID", func(t *testing.T) {
_, err := testClient.InvokeMethod(ctx, "", "fn", "get")
assert.NotNil(t, err)
require.Error(t, err)
})
t.Run("without method", func(t *testing.T) {
_, err := testClient.InvokeMethod(ctx, "test", "", "get")
assert.NotNil(t, err)
require.Error(t, err)
})
t.Run("without verb", func(t *testing.T) {
_, err := testClient.InvokeMethod(ctx, "test", "fn", "")
assert.NotNil(t, err)
require.Error(t, err)
})
t.Run("from struct with text", func(t *testing.T) {
testdata := _testCustomContentwithText{
@ -86,7 +87,7 @@ func TestInvokeMethodWithContent(t *testing.T) {
Key2: "value2",
}
_, err := testClient.InvokeMethodWithCustomContent(ctx, "test", "fn", "post", "text/plain", testdata)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("from struct with text and numbers", func(t *testing.T) {
@ -95,7 +96,7 @@ func TestInvokeMethodWithContent(t *testing.T) {
Key2: 2500,
}
_, err := testClient.InvokeMethodWithCustomContent(ctx, "test", "fn", "post", "text/plain", testdata)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("from struct with slices", func(t *testing.T) {
@ -104,7 +105,7 @@ func TestInvokeMethodWithContent(t *testing.T) {
Key2: []int{25, 40, 600},
}
_, err := testClient.InvokeMethodWithCustomContent(ctx, "test", "fn", "post", "text/plain", testdata)
assert.Nil(t, err)
require.NoError(t, err)
})
}
@ -112,27 +113,27 @@ func TestVerbParsing(t *testing.T) {
t.Run("valid lower case", func(t *testing.T) {
v := queryAndVerbToHTTPExtension("", "post")
assert.NotNil(t, v)
assert.Equal(t, v1.HTTPExtension_POST, v.Verb)
assert.Len(t, v.Querystring, 0)
assert.Equal(t, v1.HTTPExtension_POST, v.GetVerb())
assert.Empty(t, v.GetQuerystring())
})
t.Run("valid upper case", func(t *testing.T) {
v := queryAndVerbToHTTPExtension("", "GET")
assert.NotNil(t, v)
assert.Equal(t, v1.HTTPExtension_GET, v.Verb)
assert.Equal(t, v1.HTTPExtension_GET, v.GetVerb())
})
t.Run("invalid verb", func(t *testing.T) {
v := queryAndVerbToHTTPExtension("", "BAD")
assert.NotNil(t, v)
assert.Equal(t, v1.HTTPExtension_NONE, v.Verb)
assert.Equal(t, v1.HTTPExtension_NONE, v.GetVerb())
})
t.Run("valid query", func(t *testing.T) {
v := queryAndVerbToHTTPExtension("foo=bar&url=http://dapr.io", "post")
assert.NotNil(t, v)
assert.Equal(t, v1.HTTPExtension_POST, v.Verb)
assert.Equal(t, "foo=bar&url=http://dapr.io", v.Querystring)
assert.Equal(t, v1.HTTPExtension_POST, v.GetVerb())
assert.Equal(t, "foo=bar&url=http://dapr.io", v.GetQuerystring())
})
}

View File

@ -68,7 +68,7 @@ func (c *GRPCClient) TryLockAlpha1(ctx context.Context, storeName string, reques
}
return &LockResponse{
Success: resp.Success,
Success: resp.GetSuccess(),
}, nil
}
@ -94,7 +94,7 @@ func (c *GRPCClient) UnlockAlpha1(ctx context.Context, storeName string, request
}
return &UnlockResponse{
StatusCode: int32(resp.Status),
Status: pb.UnlockResponse_Status_name[int32(resp.Status)],
StatusCode: int32(resp.GetStatus()),
Status: pb.UnlockResponse_Status_name[int32(resp.GetStatus())],
}, nil
}

View File

@ -14,9 +14,10 @@ limitations under the License.
package client
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
pb "github.com/dapr/dapr/pkg/proto/runtime/v1"
@ -27,18 +28,18 @@ const (
)
func TestLock(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
t.Run("try lock invalid store name", func(t *testing.T) {
r, err := testClient.TryLockAlpha1(ctx, "", &LockRequest{})
assert.Nil(t, r)
assert.Error(t, err)
require.Error(t, err)
})
t.Run("try lock invalid request", func(t *testing.T) {
r, err := testClient.TryLockAlpha1(ctx, testLockStore, nil)
assert.Nil(t, r)
assert.Error(t, err)
require.Error(t, err)
})
t.Run("try lock", func(t *testing.T) {
@ -48,7 +49,7 @@ func TestLock(t *testing.T) {
ExpiryInSeconds: 5,
})
assert.NotNil(t, r)
assert.NoError(t, err)
require.NoError(t, err)
assert.True(t, r.Success)
})
@ -58,13 +59,13 @@ func TestLock(t *testing.T) {
ResourceID: "resource1",
})
assert.Nil(t, r)
assert.Error(t, err)
require.Error(t, err)
})
t.Run("unlock invalid request", func(t *testing.T) {
r, err := testClient.UnlockAlpha1(ctx, "testLockStore", nil)
assert.Nil(t, r)
assert.Error(t, err)
require.Error(t, err)
})
t.Run("unlock", func(t *testing.T) {
@ -73,7 +74,7 @@ func TestLock(t *testing.T) {
ResourceID: "resource1",
})
assert.NotNil(t, r)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, pb.UnlockResponse_SUCCESS.String(), r.Status)
})
}

View File

@ -5,8 +5,6 @@ import (
"errors"
"fmt"
"google.golang.org/protobuf/types/known/emptypb"
pb "github.com/dapr/dapr/pkg/proto/runtime/v1"
)
@ -54,53 +52,53 @@ type MetadataHTTPEndpoint struct {
// GetMetadata returns the metadata of the sidecar
func (c *GRPCClient) GetMetadata(ctx context.Context) (metadata *GetMetadataResponse, err error) {
resp, err := c.protoClient.GetMetadata(ctx, &emptypb.Empty{})
resp, err := c.protoClient.GetMetadata(ctx, &pb.GetMetadataRequest{})
if err != nil {
return nil, fmt.Errorf("error invoking service: %w", err)
}
if resp != nil {
activeActorsCount := make([]*MetadataActiveActorsCount, len(resp.ActiveActorsCount))
for a := range resp.ActiveActorsCount {
activeActorsCount[a] = &MetadataActiveActorsCount{
Type: resp.ActiveActorsCount[a].Type,
Count: resp.ActiveActorsCount[a].Count,
activeActorsCount := make([]*MetadataActiveActorsCount, len(resp.GetActorRuntime().GetActiveActors()))
for i, a := range resp.GetActorRuntime().GetActiveActors() {
activeActorsCount[i] = &MetadataActiveActorsCount{
Type: a.GetType(),
Count: a.GetCount(),
}
}
registeredComponents := make([]*MetadataRegisteredComponents, len(resp.RegisteredComponents))
for r := range resp.RegisteredComponents {
registeredComponents[r] = &MetadataRegisteredComponents{
Name: resp.RegisteredComponents[r].Name,
Type: resp.RegisteredComponents[r].Type,
Version: resp.RegisteredComponents[r].Version,
Capabilities: resp.RegisteredComponents[r].Capabilities,
registeredComponents := make([]*MetadataRegisteredComponents, len(resp.GetRegisteredComponents()))
for i, r := range resp.GetRegisteredComponents() {
registeredComponents[i] = &MetadataRegisteredComponents{
Name: r.GetName(),
Type: r.GetType(),
Version: r.GetVersion(),
Capabilities: r.GetCapabilities(),
}
}
subscriptions := make([]*MetadataSubscription, len(resp.Subscriptions))
for s := range resp.Subscriptions {
subscriptions := make([]*MetadataSubscription, len(resp.GetSubscriptions()))
for i, s := range resp.GetSubscriptions() {
rules := &PubsubSubscriptionRules{}
for r := range resp.Subscriptions[s].Rules.Rules {
for _, r := range s.GetRules().GetRules() {
rules.Rules = append(rules.Rules, &PubsubSubscriptionRule{
Match: resp.Subscriptions[s].Rules.Rules[r].Match,
Path: resp.Subscriptions[s].Rules.Rules[r].Path,
Match: r.GetMatch(),
Path: r.GetPath(),
})
}
subscriptions[s] = &MetadataSubscription{
PubsubName: resp.Subscriptions[s].PubsubName,
Topic: resp.Subscriptions[s].Topic,
Metadata: resp.Subscriptions[s].Metadata,
subscriptions[i] = &MetadataSubscription{
PubsubName: s.GetPubsubName(),
Topic: s.GetTopic(),
Metadata: s.GetMetadata(),
Rules: rules,
DeadLetterTopic: resp.Subscriptions[s].DeadLetterTopic,
DeadLetterTopic: s.GetDeadLetterTopic(),
}
}
httpEndpoints := make([]*MetadataHTTPEndpoint, len(resp.HttpEndpoints))
for e := range resp.HttpEndpoints {
httpEndpoints[e] = &MetadataHTTPEndpoint{
Name: resp.HttpEndpoints[e].Name,
httpEndpoints := make([]*MetadataHTTPEndpoint, len(resp.GetHttpEndpoints()))
for i, e := range resp.GetHttpEndpoints() {
httpEndpoints[i] = &MetadataHTTPEndpoint{
Name: e.GetName(),
}
}
metadata = &GetMetadataResponse{
ID: resp.Id,
ID: resp.GetId(),
ActiveActorsCount: activeActorsCount,
RegisteredComponents: registeredComponents,
ExtendedMetadata: resp.GetExtendedMetadata(),

View File

@ -1,29 +1,30 @@
package client
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
)
// Test GetMetadata returns
func TestGetMetadata(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
t.Run("get meta", func(t *testing.T) {
metadata, err := testClient.GetMetadata(ctx)
assert.NoError(t, err)
require.NoError(t, err)
assert.NotNil(t, metadata)
})
}
func TestSetMetadata(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
t.Run("set meta", func(t *testing.T) {
err := testClient.SetMetadata(ctx, "test_key", "test_value")
assert.NoError(t, err)
require.NoError(t, err)
metadata, err := testClient.GetMetadata(ctx)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, "test_value", metadata.ExtendedMetadata["test_key"])
})
}

View File

@ -66,7 +66,7 @@ func (c *GRPCClient) PublishEvent(ctx context.Context, pubsubName, topicName str
}
}
_, err := c.protoClient.PublishEvent(c.withAuthToken(ctx), request)
_, err := c.protoClient.PublishEvent(ctx, request)
if err != nil {
return fmt.Errorf("error publishing event unto %s topic: %w", topicName, err)
}
@ -91,7 +91,7 @@ func PublishEventWithMetadata(metadata map[string]string) PublishEventOption {
// PublishEventWithRawPayload can be passed as option to PublishEvent to set rawPayload metadata.
func PublishEventWithRawPayload() PublishEventOption {
return func(e *pb.PublishEventRequest) {
if e.Metadata == nil {
if e.GetMetadata() == nil {
e.Metadata = map[string]string{rawPayload: trueValue}
} else {
e.Metadata[rawPayload] = trueValue
@ -156,7 +156,7 @@ func (c *GRPCClient) PublishEvents(ctx context.Context, pubsubName, topicName st
failedEvents = append(failedEvents, event)
continue
}
eventMap[entry.EntryId] = event
eventMap[entry.GetEntryId()] = event
entries = append(entries, entry)
}
@ -169,7 +169,7 @@ func (c *GRPCClient) PublishEvents(ctx context.Context, pubsubName, topicName st
o(request)
}
res, err := c.protoClient.BulkPublishEventAlpha1(c.withAuthToken(ctx), request)
res, err := c.protoClient.BulkPublishEventAlpha1(ctx, request)
// If there is an error, all events failed to publish.
if err != nil {
return PublishEventsResponse{
@ -178,11 +178,11 @@ func (c *GRPCClient) PublishEvents(ctx context.Context, pubsubName, topicName st
}
}
for _, failedEntry := range res.FailedEntries {
event, ok := eventMap[failedEntry.EntryId]
for _, failedEntry := range res.GetFailedEntries() {
event, ok := eventMap[failedEntry.GetEntryId()]
if !ok {
// This should never happen.
failedEvents = append(failedEvents, failedEntry.EntryId)
failedEvents = append(failedEvents, failedEntry.GetEntryId())
}
failedEvents = append(failedEvents, event)
}
@ -224,12 +224,12 @@ func createBulkPublishRequestEntry(data interface{}) (*pb.BulkPublishRequestEntr
return &pb.BulkPublishRequestEntry{}, fmt.Errorf("error serializing input struct: %w", err)
}
if isCloudEvent(entry.Event) {
if isCloudEvent(entry.GetEvent()) {
entry.ContentType = "application/cloudevents+json"
}
}
if entry.EntryId == "" {
if entry.GetEntryId() == "" {
entry.EntryId = uuid.New().String()
}
@ -239,7 +239,7 @@ func createBulkPublishRequestEntry(data interface{}) (*pb.BulkPublishRequestEntr
// PublishEventsWithContentType can be passed as option to PublishEvents to explicitly set the same Content-Type for all events.
func PublishEventsWithContentType(contentType string) PublishEventsOption {
return func(r *pb.BulkPublishRequest) {
for _, entry := range r.Entries {
for _, entry := range r.GetEntries() {
entry.ContentType = contentType
}
}
@ -255,7 +255,7 @@ func PublishEventsWithMetadata(metadata map[string]string) PublishEventsOption {
// PublishEventsWithRawPayload can be passed as option to PublishEvents to set rawPayload request metadata.
func PublishEventsWithRawPayload() PublishEventsOption {
return func(r *pb.BulkPublishRequest) {
if r.Metadata == nil {
if r.GetMetadata() == nil {
r.Metadata = map[string]string{rawPayload: trueValue}
} else {
r.Metadata[rawPayload] = trueValue

View File

@ -14,9 +14,10 @@ limitations under the License.
package client
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
)
@ -37,21 +38,21 @@ type _testCustomContentwithSlices struct {
// go test -timeout 30s ./client -count 1 -run ^TestPublishEvent$
func TestPublishEvent(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
t.Run("with data", func(t *testing.T) {
err := testClient.PublishEvent(ctx, "messages", "test", []byte("ping"))
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("without data", func(t *testing.T) {
err := testClient.PublishEvent(ctx, "messages", "test", nil)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("with empty topic name", func(t *testing.T) {
err := testClient.PublishEvent(ctx, "messages", "", []byte("ping"))
assert.NotNil(t, err)
require.Error(t, err)
})
t.Run("from struct with text", func(t *testing.T) {
@ -60,7 +61,7 @@ func TestPublishEvent(t *testing.T) {
Key2: "value2",
}
err := testClient.PublishEventfromCustomContent(ctx, "messages", "test", testdata)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("from struct with text and numbers", func(t *testing.T) {
@ -69,7 +70,7 @@ func TestPublishEvent(t *testing.T) {
Key2: 2500,
}
err := testClient.PublishEventfromCustomContent(ctx, "messages", "test", testdata)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("from struct with slices", func(t *testing.T) {
@ -78,27 +79,27 @@ func TestPublishEvent(t *testing.T) {
Key2: []int{25, 40, 600},
}
err := testClient.PublishEventfromCustomContent(ctx, "messages", "test", testdata)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("error serializing JSON", func(t *testing.T) {
err := testClient.PublishEventfromCustomContent(ctx, "messages", "test", make(chan struct{}))
assert.Error(t, err)
require.Error(t, err)
})
t.Run("raw payload", func(t *testing.T) {
err := testClient.PublishEvent(ctx, "messages", "test", []byte("ping"), PublishEventWithRawPayload())
assert.Nil(t, err)
require.NoError(t, err)
})
}
// go test -timeout 30s ./client -count 1 -run ^TestPublishEvents$
func TestPublishEvents(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
t.Run("without pubsub name", func(t *testing.T) {
res := testClient.PublishEvents(ctx, "", "test", []interface{}{"ping", "pong"})
assert.Error(t, res.Error)
require.Error(t, res.Error)
assert.Len(t, res.FailedEvents, 2)
assert.Contains(t, res.FailedEvents, "ping")
assert.Contains(t, res.FailedEvents, "pong")
@ -106,7 +107,7 @@ func TestPublishEvents(t *testing.T) {
t.Run("without topic name", func(t *testing.T) {
res := testClient.PublishEvents(ctx, "messages", "", []interface{}{"ping", "pong"})
assert.Error(t, res.Error)
require.Error(t, res.Error)
assert.Len(t, res.FailedEvents, 2)
assert.Contains(t, res.FailedEvents, "ping")
assert.Contains(t, res.FailedEvents, "pong")
@ -114,14 +115,14 @@ func TestPublishEvents(t *testing.T) {
t.Run("with data", func(t *testing.T) {
res := testClient.PublishEvents(ctx, "messages", "test", []interface{}{"ping", "pong"})
assert.Nil(t, res.Error)
assert.Len(t, res.FailedEvents, 0)
require.NoError(t, res.Error)
assert.Empty(t, res.FailedEvents)
})
t.Run("without data", func(t *testing.T) {
res := testClient.PublishEvents(ctx, "messages", "test", nil)
assert.Nil(t, res.Error)
assert.Len(t, res.FailedEvents, 0)
require.NoError(t, res.Error)
assert.Empty(t, res.FailedEvents)
})
t.Run("with struct data", func(t *testing.T) {
@ -155,47 +156,47 @@ func TestPublishEvents(t *testing.T) {
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
res := testClient.PublishEvents(ctx, "messages", "test", []interface{}{tc.data})
assert.Nil(t, res.Error)
assert.Len(t, res.FailedEvents, 0)
require.NoError(t, res.Error)
assert.Empty(t, res.FailedEvents)
})
}
})
t.Run("error serializing one event", func(t *testing.T) {
res := testClient.PublishEvents(ctx, "messages", "test", []interface{}{make(chan struct{}), "pong"})
assert.Error(t, res.Error)
require.Error(t, res.Error)
assert.Len(t, res.FailedEvents, 1)
assert.IsType(t, make(chan struct{}), res.FailedEvents[0])
})
t.Run("with raw payload", func(t *testing.T) {
res := testClient.PublishEvents(ctx, "messages", "test", []interface{}{"ping", "pong"}, PublishEventsWithRawPayload())
assert.Nil(t, res.Error)
assert.Len(t, res.FailedEvents, 0)
require.NoError(t, res.Error)
assert.Empty(t, res.FailedEvents)
})
t.Run("with metadata", func(t *testing.T) {
res := testClient.PublishEvents(ctx, "messages", "test", []interface{}{"ping", "pong"}, PublishEventsWithMetadata(map[string]string{"key": "value"}))
assert.Nil(t, res.Error)
assert.Len(t, res.FailedEvents, 0)
require.NoError(t, res.Error)
assert.Empty(t, res.FailedEvents)
})
t.Run("with custom content type", func(t *testing.T) {
res := testClient.PublishEvents(ctx, "messages", "test", []interface{}{"ping", "pong"}, PublishEventsWithContentType("text/plain"))
assert.Nil(t, res.Error)
assert.Len(t, res.FailedEvents, 0)
require.NoError(t, res.Error)
assert.Empty(t, res.FailedEvents)
})
t.Run("with events that will fail some events", func(t *testing.T) {
res := testClient.PublishEvents(ctx, "messages", "test", []interface{}{"ping", "pong", "fail-ping"})
assert.Error(t, res.Error)
require.Error(t, res.Error)
assert.Len(t, res.FailedEvents, 1)
assert.Contains(t, res.FailedEvents, "fail-ping")
})
t.Run("with events that will fail the entire request", func(t *testing.T) {
res := testClient.PublishEvents(ctx, "messages", "test", []interface{}{"ping", "pong", "failall-ping"})
assert.Error(t, res.Error)
require.Error(t, res.Error)
assert.Len(t, res.FailedEvents, 3)
assert.Contains(t, res.FailedEvents, "ping")
assert.Contains(t, res.FailedEvents, "pong")
@ -275,11 +276,11 @@ func TestCreateBulkPublishRequestEntry(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
entry, err := createBulkPublishRequestEntry(tc.data)
if tc.expectedError {
assert.Error(t, err)
require.Error(t, err)
} else {
assert.Nil(t, err)
assert.Equal(t, tc.expectedEvent, entry.Event)
assert.Equal(t, tc.expectedContentType, entry.ContentType)
require.NoError(t, err)
assert.Equal(t, tc.expectedEvent, entry.GetEvent())
assert.Equal(t, tc.expectedContentType, entry.GetContentType())
}
})
}
@ -292,9 +293,9 @@ func TestCreateBulkPublishRequestEntry(t *testing.T) {
EntryID: "123",
Metadata: map[string]string{"key": "value"},
})
assert.Nil(t, err)
assert.Equal(t, "123", entry.EntryId)
assert.Equal(t, map[string]string{"key": "value"}, entry.Metadata)
require.NoError(t, err)
assert.Equal(t, "123", entry.GetEntryId())
assert.Equal(t, map[string]string{"key": "value"}, entry.GetMetadata())
})
t.Run("should set random uuid as entryID when not provided", func(t *testing.T) {
@ -318,12 +319,12 @@ func TestCreateBulkPublishRequestEntry(t *testing.T) {
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
entry, err := createBulkPublishRequestEntry(tc.data)
assert.Nil(t, err)
assert.NotEmpty(t, entry.EntryId)
assert.Nil(t, entry.Metadata)
require.NoError(t, err)
assert.NotEmpty(t, entry.GetEntryId())
assert.Nil(t, entry.GetMetadata())
_, err = uuid.Parse(entry.EntryId)
assert.Nil(t, err)
_, err = uuid.Parse(entry.GetEntryId())
require.NoError(t, err)
})
}
})

90
client/scheduling.go Normal file
View File

@ -0,0 +1,90 @@
/*
Copyright 2021 The Dapr Authors
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 client
import (
"context"
"log"
"google.golang.org/protobuf/types/known/anypb"
pb "github.com/dapr/dapr/pkg/proto/runtime/v1"
)
type Job struct {
Name string
Schedule string // Optional
Repeats uint32 // Optional
DueTime string // Optional
TTL string // Optional
Data *anypb.Any
}
// ScheduleJobAlpha1 raises and schedules a job.
func (c *GRPCClient) ScheduleJobAlpha1(ctx context.Context, job *Job) error {
// TODO: Assert job fields are defined: Name, Data
jobRequest := &pb.Job{
Name: job.Name,
Data: job.Data,
}
if job.Schedule != "" {
jobRequest.Schedule = &job.Schedule
}
if job.Repeats != 0 {
jobRequest.Repeats = &job.Repeats
}
if job.DueTime != "" {
jobRequest.DueTime = &job.DueTime
}
if job.TTL != "" {
jobRequest.Ttl = &job.TTL
}
_, err := c.protoClient.ScheduleJobAlpha1(ctx, &pb.ScheduleJobRequest{
Job: jobRequest,
})
return err
}
// GetJobAlpha1 retrieves a scheduled job.
func (c *GRPCClient) GetJobAlpha1(ctx context.Context, name string) (*Job, error) {
// TODO: Name validation
resp, err := c.protoClient.GetJobAlpha1(ctx, &pb.GetJobRequest{
Name: name,
})
log.Println(resp)
if err != nil {
return nil, err
}
return &Job{
Name: resp.GetJob().GetName(),
Schedule: resp.GetJob().GetSchedule(),
Repeats: resp.GetJob().GetRepeats(),
DueTime: resp.GetJob().GetDueTime(),
TTL: resp.GetJob().GetTtl(),
Data: resp.GetJob().GetData(),
}, nil
}
// DeleteJobAlpha1 deletes a scheduled job.
func (c *GRPCClient) DeleteJobAlpha1(ctx context.Context, name string) error {
// TODO: Name validation
_, err := c.protoClient.DeleteJobAlpha1(ctx, &pb.DeleteJobRequest{
Name: name,
})
return err
}

57
client/scheduling_test.go Normal file
View File

@ -0,0 +1,57 @@
/*
Copyright 2021 The Dapr Authors
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 client
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/anypb"
)
func TestSchedulingAlpha1(t *testing.T) {
ctx := t.Context()
t.Run("schedule job - valid", func(t *testing.T) {
err := testClient.ScheduleJobAlpha1(ctx, &Job{
Name: "test",
Schedule: "test",
Data: &anypb.Any{},
})
require.NoError(t, err)
})
t.Run("get job - valid", func(t *testing.T) {
expected := &Job{
Name: "name",
Schedule: "@every 10s",
Repeats: 4,
DueTime: "10s",
TTL: "10s",
Data: nil,
}
resp, err := testClient.GetJobAlpha1(ctx, "name")
require.NoError(t, err)
assert.Equal(t, expected, resp)
})
t.Run("delete job - valid", func(t *testing.T) {
err := testClient.DeleteJobAlpha1(ctx, "name")
require.NoError(t, err)
})
}

View File

@ -36,7 +36,7 @@ func (c *GRPCClient) GetSecret(ctx context.Context, storeName, key string, meta
Metadata: meta,
}
resp, err := c.protoClient.GetSecret(c.withAuthToken(ctx), req)
resp, err := c.protoClient.GetSecret(ctx, req)
if err != nil {
return nil, fmt.Errorf("error invoking service: %w", err)
}
@ -59,7 +59,7 @@ func (c *GRPCClient) GetBulkSecret(ctx context.Context, storeName string, meta m
Metadata: meta,
}
resp, err := c.protoClient.GetBulkSecret(c.withAuthToken(ctx), req)
resp, err := c.protoClient.GetBulkSecret(ctx, req)
if err != nil {
return nil, fmt.Errorf("error invoking service: %w", err)
}
@ -67,10 +67,10 @@ func (c *GRPCClient) GetBulkSecret(ctx context.Context, storeName string, meta m
if resp != nil {
data = map[string]map[string]string{}
for secretName, secretResponse := range resp.Data {
for secretName, secretResponse := range resp.GetData() {
data[secretName] = map[string]string{}
for k, v := range secretResponse.Secrets {
for k, v := range secretResponse.GetSecrets() {
data[secretName][k] = v
}
}

View File

@ -14,61 +14,62 @@ limitations under the License.
package client
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
)
// go test -timeout 30s ./client -count 1 -run ^TestGetSecret$
func TestGetSecret(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
t.Run("without store", func(t *testing.T) {
out, err := testClient.GetSecret(ctx, "", "key1", nil)
assert.Error(t, err)
require.Error(t, err)
assert.Nil(t, out)
})
t.Run("without key", func(t *testing.T) {
out, err := testClient.GetSecret(ctx, "store", "", nil)
assert.Error(t, err)
require.Error(t, err)
assert.Nil(t, out)
})
t.Run("without meta", func(t *testing.T) {
out, err := testClient.GetSecret(ctx, "store", "key1", nil)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, out)
})
t.Run("with meta", func(t *testing.T) {
in := map[string]string{"k1": "v1", "k2": "v2"}
out, err := testClient.GetSecret(ctx, "store", "key1", in)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, out)
})
}
func TestGetBulkSecret(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
t.Run("without store", func(t *testing.T) {
out, err := testClient.GetBulkSecret(ctx, "", nil)
assert.Error(t, err)
require.Error(t, err)
assert.Nil(t, out)
})
t.Run("without meta", func(t *testing.T) {
out, err := testClient.GetBulkSecret(ctx, "store", nil)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, out)
})
t.Run("with meta", func(t *testing.T) {
in := map[string]string{"k1": "v1", "k2": "v2"}
out, err := testClient.GetBulkSecret(ctx, "store", in)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, out)
})
}

View File

@ -17,9 +17,10 @@ import (
"context"
"errors"
"fmt"
"math"
"time"
"github.com/golang/protobuf/ptypes/duration"
"google.golang.org/protobuf/types/known/durationpb"
v1 "github.com/dapr/dapr/pkg/proto/common/v1"
pb "github.com/dapr/dapr/pkg/proto/runtime/v1"
@ -46,17 +47,30 @@ const (
StateOperationTypeUpsert OperationType = 1
// StateOperationTypeDelete represents delete operation type value.
StateOperationTypeDelete OperationType = 2
// EventualType represents the eventual type value.
EventualType = "eventual"
// StrongType represents the strong type value.
StrongType = "strong"
// FirstWriteType represents the first write type value.
FirstWriteType = "first-write"
// LastWriteType represents the last write type value.
LastWriteType = "last-write"
// UpsertType represents the upsert type value.
UpsertType = "upsert"
// DeleteType represents the delete type value.
DeleteType = "delete"
// UndefinedType represents undefined type value.
UndefinedType = "undefined"
)
type (
// StateConsistency is the consistency enum type.
StateConsistency int
StateConsistency int32
// StateConcurrency is the concurrency enum type.
StateConcurrency int
StateConcurrency int32
// OperationType is the operation enum type.
OperationType int
OperationType int32
)
// GetPBConsistency get consistency pb value.
@ -73,8 +87,8 @@ func (s StateConcurrency) GetPBConcurrency() v1.StateOptions_StateConcurrency {
func (o OperationType) String() string {
names := [...]string{
UndefinedType,
"upsert",
"delete",
UpsertType,
DeleteType,
}
if o < StateOperationTypeUpsert || o > StateOperationTypeDelete {
return UndefinedType
@ -87,10 +101,10 @@ func (o OperationType) String() string {
func (s StateConsistency) String() string {
names := [...]string{
UndefinedType,
"strong",
"eventual",
EventualType,
StrongType,
}
if s < StateConsistencyStrong || s > StateConsistencyEventual {
if s < StateConsistencyEventual || s > StateConsistencyStrong {
return UndefinedType
}
@ -101,8 +115,8 @@ func (s StateConsistency) String() string {
func (s StateConcurrency) String() string {
names := [...]string{
UndefinedType,
"first-write",
"last-write",
FirstWriteType,
LastWriteType,
}
if s < StateConcurrencyFirstWrite || s > StateConcurrencyLastWrite {
return UndefinedType
@ -235,13 +249,19 @@ func copyStateOptionDefault() *StateOptions {
}
}
func toProtoDuration(d time.Duration) *duration.Duration {
func toProtoDuration(d time.Duration) *durationpb.Duration {
nanos := d.Nanoseconds()
secs := nanos / 1e9
nanos -= secs * 1e9
return &duration.Duration{
// conversion check - gosec ignored below for conversion
if nanos <= int64(math.MinInt32) && nanos >= int64(math.MaxInt32) {
panic("integer overflow converting duration to proto")
}
return &durationpb.Duration{
Seconds: secs,
Nanos: int32(nanos),
Nanos: int32(nanos), //nolint:gosec
}
}
@ -268,7 +288,7 @@ func (c *GRPCClient) ExecuteStateTransaction(ctx context.Context, storeName stri
StoreName: storeName,
Operations: items,
}
_, err := c.protoClient.ExecuteStateTransaction(c.withAuthToken(ctx), req)
_, err := c.protoClient.ExecuteStateTransaction(ctx, req)
if err != nil {
return fmt.Errorf("error executing state transaction: %w", err)
}
@ -317,10 +337,10 @@ func (c *GRPCClient) SaveBulkState(ctx context.Context, storeName string, items
for _, si := range items {
item := toProtoSaveStateItem(si)
req.States = append(req.States, item)
req.States = append(req.GetStates(), item)
}
_, err := c.protoClient.SaveState(c.withAuthToken(ctx), req)
_, err := c.protoClient.SaveState(ctx, req)
if err != nil {
return fmt.Errorf("error saving state: %w", err)
}
@ -344,22 +364,22 @@ func (c *GRPCClient) GetBulkState(ctx context.Context, storeName string, keys []
Parallelism: parallelism,
}
results, err := c.protoClient.GetBulkState(c.withAuthToken(ctx), req)
results, err := c.protoClient.GetBulkState(ctx, req)
if err != nil {
return nil, fmt.Errorf("error getting state: %w", err)
}
if results == nil || results.Items == nil {
if results == nil || results.GetItems() == nil {
return items, nil
}
for _, r := range results.Items {
for _, r := range results.GetItems() {
item := &BulkStateItem{
Key: r.Key,
Etag: r.Etag,
Value: r.Data,
Metadata: r.Metadata,
Error: r.Error,
Key: r.GetKey(),
Etag: r.GetEtag(),
Value: r.GetData(),
Metadata: r.GetMetadata(),
Error: r.GetError(),
}
items = append(items, item)
}
@ -369,7 +389,8 @@ func (c *GRPCClient) GetBulkState(ctx context.Context, storeName string, keys []
// GetState retrieves state from specific store using default consistency option.
func (c *GRPCClient) GetState(ctx context.Context, storeName, key string, meta map[string]string) (item *StateItem, err error) {
return c.GetStateWithConsistency(ctx, storeName, key, meta, StateConsistencyStrong)
i, err := c.GetStateWithConsistency(ctx, storeName, key, meta, StateConsistencyStrong)
return i, err
}
// GetStateWithConsistency retrieves state from specific store using provided state consistency.
@ -385,16 +406,16 @@ func (c *GRPCClient) GetStateWithConsistency(ctx context.Context, storeName, key
Metadata: meta,
}
result, err := c.protoClient.GetState(c.withAuthToken(ctx), req)
result, err := c.protoClient.GetState(ctx, req)
if err != nil {
return nil, fmt.Errorf("error getting state: %w", err)
}
return &StateItem{
Etag: result.Etag,
Etag: result.GetEtag(),
Key: key,
Value: result.Data,
Metadata: result.Metadata,
Value: result.GetData(),
Metadata: result.GetMetadata(),
}, nil
}
@ -411,21 +432,21 @@ func (c *GRPCClient) QueryStateAlpha1(ctx context.Context, storeName, query stri
Query: query,
Metadata: meta,
}
resp, err := c.protoClient.QueryStateAlpha1(c.withAuthToken(ctx), req)
resp, err := c.protoClient.QueryStateAlpha1(ctx, req)
if err != nil {
return nil, fmt.Errorf("error querying state: %w", err)
}
ret := &QueryResponse{
Results: make([]QueryItem, len(resp.Results)),
Token: resp.Token,
Metadata: resp.Metadata,
Results: make([]QueryItem, len(resp.GetResults())),
Token: resp.GetToken(),
Metadata: resp.GetMetadata(),
}
for i, item := range resp.Results {
ret.Results[i].Key = item.Key
ret.Results[i].Value = item.Data
ret.Results[i].Etag = item.Etag
ret.Results[i].Error = item.Error
for i, item := range resp.GetResults() {
ret.Results[i].Key = item.GetKey()
ret.Results[i].Value = item.GetData()
ret.Results[i].Etag = item.GetEtag()
ret.Results[i].Error = item.GetError()
}
return ret, nil
@ -455,7 +476,7 @@ func (c *GRPCClient) DeleteStateWithETag(ctx context.Context, storeName, key str
}
}
_, err := c.protoClient.DeleteState(c.withAuthToken(ctx), req)
_, err := c.protoClient.DeleteState(ctx, req)
if err != nil {
return fmt.Errorf("error deleting state: %w", err)
}
@ -470,7 +491,7 @@ func (c *GRPCClient) DeleteBulkState(ctx context.Context, storeName string, keys
}
items := make([]*DeleteStateItem, 0, len(keys))
for i := 0; i < len(keys); i++ {
for i := range keys {
item := &DeleteStateItem{
Key: keys[i],
Metadata: meta,
@ -488,7 +509,7 @@ func (c *GRPCClient) DeleteBulkStateItems(ctx context.Context, storeName string,
}
states := make([]*v1.StateItem, 0, len(items))
for i := 0; i < len(items); i++ {
for i := range items {
item := items[i]
if err := hasRequiredStateArgs(storeName, item.Key); err != nil {
return fmt.Errorf("missing required arguments: %w", err)
@ -511,7 +532,7 @@ func (c *GRPCClient) DeleteBulkStateItems(ctx context.Context, storeName string,
StoreName: storeName,
States: states,
}
_, err := c.protoClient.DeleteBulkState(c.withAuthToken(ctx), req)
_, err := c.protoClient.DeleteBulkState(ctx, req)
return err
}

View File

@ -14,10 +14,11 @@ limitations under the License.
package client
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
v1 "github.com/dapr/dapr/pkg/proto/common/v1"
@ -29,19 +30,37 @@ const (
)
func TestTypes(t *testing.T) {
var op OperationType = -1
assert.Equal(t, UndefinedType, op.String())
var c StateConcurrency = -1
assert.Equal(t, UndefinedType, c.String())
var d StateConsistency = -1
assert.Equal(t, UndefinedType, d.String())
t.Run("test operation types", func(t *testing.T) {
var a OperationType = -1
assert.Equal(t, UndefinedType, a.String())
a = 1
assert.Equal(t, UpsertType, a.String())
a = 2
assert.Equal(t, DeleteType, a.String())
})
t.Run("test state concurrency type", func(t *testing.T) {
var b StateConcurrency = -1
assert.Equal(t, UndefinedType, b.String())
b = 1
assert.Equal(t, FirstWriteType, b.String())
b = 2
assert.Equal(t, LastWriteType, b.String())
})
t.Run("test state consistency type", func(t *testing.T) {
var c StateConsistency = -1
assert.Equal(t, UndefinedType, c.String())
c = 1
assert.Equal(t, EventualType, c.String())
c = 2
assert.Equal(t, StrongType, c.String())
})
}
func TestDurationConverter(t *testing.T) {
d := 10 * time.Second
pd := toProtoDuration(d)
assert.NotNil(t, pd)
assert.Equal(t, pd.Seconds, int64(10))
assert.Equal(t, int64(10), pd.GetSeconds())
}
func TestStateOptionsConverter(t *testing.T) {
@ -51,25 +70,25 @@ func TestStateOptionsConverter(t *testing.T) {
}
p := toProtoStateOptions(s)
assert.NotNil(t, p)
assert.Equal(t, p.Concurrency, v1.StateOptions_CONCURRENCY_LAST_WRITE)
assert.Equal(t, p.Consistency, v1.StateOptions_CONSISTENCY_STRONG)
assert.Equal(t, v1.StateOptions_CONCURRENCY_LAST_WRITE, p.GetConcurrency())
assert.Equal(t, v1.StateOptions_CONSISTENCY_STRONG, p.GetConsistency())
}
// go test -timeout 30s ./client -count 1 -run ^TestSaveState$
func TestSaveState(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
data := testData
store := testStore
key := "key1"
t.Run("save data", func(t *testing.T) {
err := testClient.SaveState(ctx, store, key, []byte(data), nil)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("get saved data", func(t *testing.T) {
item, err := testClient.GetState(ctx, store, key, nil)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, item)
assert.NotEmpty(t, item.Etag)
assert.Equal(t, item.Key, key)
@ -78,7 +97,7 @@ func TestSaveState(t *testing.T) {
t.Run("get saved data with consistency", func(t *testing.T) {
item, err := testClient.GetStateWithConsistency(ctx, store, key, nil, StateConsistencyStrong)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, item)
assert.NotEmpty(t, item.Etag)
assert.Equal(t, item.Key, key)
@ -87,39 +106,39 @@ func TestSaveState(t *testing.T) {
t.Run("save data with version", func(t *testing.T) {
err := testClient.SaveStateWithETag(ctx, store, key, []byte(data), "1", nil)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("delete data", func(t *testing.T) {
err := testClient.DeleteState(ctx, store, key, nil)
assert.Nil(t, err)
require.NoError(t, err)
})
}
// go test -timeout 30s ./client -count 1 -run ^TestDeleteState$
func TestDeleteState(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
data := testData
store := testStore
key := "key1"
t.Run("delete not exist data", func(t *testing.T) {
err := testClient.DeleteState(ctx, store, key, nil)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("delete not exist data with etag and meta", func(t *testing.T) {
err := testClient.DeleteStateWithETag(ctx, store, key, &ETag{Value: "100"}, map[string]string{"meta1": "value1"},
&StateOptions{Concurrency: StateConcurrencyFirstWrite, Consistency: StateConsistencyEventual})
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("save data", func(t *testing.T) {
err := testClient.SaveState(ctx, store, key, []byte(data), nil)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("confirm data saved", func(t *testing.T) {
item, err := testClient.GetState(ctx, store, key, nil)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, item)
assert.NotEmpty(t, item.Etag)
assert.Equal(t, item.Key, key)
@ -128,11 +147,11 @@ func TestDeleteState(t *testing.T) {
t.Run("delete exist data", func(t *testing.T) {
err := testClient.DeleteState(ctx, store, key, nil)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("confirm data deleted", func(t *testing.T) {
item, err := testClient.GetState(ctx, store, key, nil)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, item)
assert.NotEmpty(t, item.Etag)
assert.Equal(t, item.Key, key)
@ -142,11 +161,11 @@ func TestDeleteState(t *testing.T) {
t.Run("save data again with etag, meta", func(t *testing.T) {
meta := map[string]string{"meta1": "value1"}
err := testClient.SaveStateWithETag(ctx, store, key, []byte(data), "1", meta, WithConsistency(StateConsistencyEventual), WithConcurrency(StateConcurrencyFirstWrite))
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("confirm data saved", func(t *testing.T) {
item, err := testClient.GetStateWithConsistency(ctx, store, key, map[string]string{"meta1": "value1"}, StateConsistencyEventual)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, item)
assert.NotEmpty(t, item.Etag)
assert.Equal(t, item.Key, key)
@ -156,11 +175,11 @@ func TestDeleteState(t *testing.T) {
t.Run("delete exist data with etag and meta", func(t *testing.T) {
err := testClient.DeleteStateWithETag(ctx, store, key, &ETag{Value: "100"}, map[string]string{"meta1": "value1"},
&StateOptions{Concurrency: StateConcurrencyFirstWrite, Consistency: StateConsistencyEventual})
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("confirm data deleted", func(t *testing.T) {
item, err := testClient.GetStateWithConsistency(ctx, store, key, map[string]string{"meta1": "value1"}, StateConsistencyEventual)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, item)
assert.NotEmpty(t, item.Etag)
assert.Equal(t, item.Key, key)
@ -169,14 +188,14 @@ func TestDeleteState(t *testing.T) {
}
func TestDeleteBulkState(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
data := testData
store := testStore
keys := []string{"key1", "key2", "key3"}
t.Run("delete not exist data", func(t *testing.T) {
err := testClient.DeleteBulkState(ctx, store, keys, nil)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("delete not exist data with stateIem", func(t *testing.T) {
@ -192,7 +211,48 @@ func TestDeleteBulkState(t *testing.T) {
})
}
err := testClient.DeleteBulkStateItems(ctx, store, items)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("delete bulk state item (empty) store", func(t *testing.T) { // save data
// save data
items := make([]*SetStateItem, 0, len(keys))
for _, key := range keys {
items = append(items, &SetStateItem{
Key: key,
Value: []byte(data),
Metadata: map[string]string{},
Etag: &ETag{Value: "1"},
Options: &StateOptions{
Concurrency: StateConcurrencyFirstWrite,
Consistency: StateConsistencyEventual,
},
})
}
err := testClient.SaveBulkState(ctx, store, items...)
require.NoError(t, err)
// confirm data saved
getItems, err := testClient.GetBulkState(ctx, store, keys, nil, 1)
require.NoError(t, err)
assert.Equal(t, len(keys), len(getItems))
// delete
deleteItems := make([]*DeleteStateItem, 0, len(keys))
for _, key := range keys {
deleteItems = append(deleteItems, &DeleteStateItem{
Key: key,
Metadata: map[string]string{},
Etag: &ETag{Value: "1"},
Options: &StateOptions{
Concurrency: StateConcurrencyFirstWrite,
Consistency: StateConsistencyEventual,
},
})
}
err = testClient.DeleteBulkStateItems(ctx, "", deleteItems)
require.Error(t, err)
})
t.Run("delete exist data", func(t *testing.T) {
@ -211,21 +271,21 @@ func TestDeleteBulkState(t *testing.T) {
})
}
err := testClient.SaveBulkState(ctx, store, items...)
assert.Nil(t, err)
require.NoError(t, err)
// confirm data saved
getItems, err := testClient.GetBulkState(ctx, store, keys, nil, 1)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, len(keys), len(getItems))
// delete
err = testClient.DeleteBulkState(ctx, store, keys, nil)
assert.NoError(t, err)
require.NoError(t, err)
// confirm data deleted
getItems, err = testClient.GetBulkState(ctx, store, keys, nil, 1)
assert.NoError(t, err)
assert.Equal(t, 0, len(getItems))
require.NoError(t, err)
assert.Empty(t, getItems)
})
t.Run("delete exist data with stateItem", func(t *testing.T) {
@ -244,11 +304,11 @@ func TestDeleteBulkState(t *testing.T) {
})
}
err := testClient.SaveBulkState(ctx, store, items...)
assert.Nil(t, err)
require.NoError(t, err)
// confirm data saved
getItems, err := testClient.GetBulkState(ctx, store, keys, nil, 1)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, len(keys), len(getItems))
// delete
@ -265,18 +325,18 @@ func TestDeleteBulkState(t *testing.T) {
})
}
err = testClient.DeleteBulkStateItems(ctx, store, deleteItems)
assert.Nil(t, err)
require.NoError(t, err)
// confirm data deleted
getItems, err = testClient.GetBulkState(ctx, store, keys, nil, 1)
assert.NoError(t, err)
assert.Equal(t, 0, len(getItems))
require.NoError(t, err)
assert.Empty(t, getItems)
})
}
// go test -timeout 30s ./client -count 1 -run ^TestStateTransactions$
func TestStateTransactions(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
data := `{ "message": "test" }`
store := testStore
meta := map[string]string{}
@ -296,16 +356,16 @@ func TestStateTransactions(t *testing.T) {
t.Run("exec inserts", func(t *testing.T) {
err := testClient.ExecuteStateTransaction(ctx, store, meta, adds)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("exec upserts", func(t *testing.T) {
items, err := testClient.GetBulkState(ctx, store, keys, nil, 10)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, items)
assert.Len(t, items, len(keys))
upsers := make([]*StateOperation, 0)
upserts := make([]*StateOperation, 0)
for _, item := range items {
op := &StateOperation{
Type: StateOperationTypeUpsert,
@ -317,15 +377,15 @@ func TestStateTransactions(t *testing.T) {
Value: item.Value,
},
}
upsers = append(upsers, op)
upserts = append(upserts, op)
}
err = testClient.ExecuteStateTransaction(ctx, store, meta, upsers)
assert.Nil(t, err)
err = testClient.ExecuteStateTransaction(ctx, store, meta, upserts)
require.NoError(t, err)
})
t.Run("get and validate inserts", func(t *testing.T) {
items, err := testClient.GetBulkState(ctx, store, keys, nil, 10)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, items)
assert.Len(t, items, len(keys))
assert.Equal(t, data, string(items[0].Value))
@ -337,19 +397,19 @@ func TestStateTransactions(t *testing.T) {
t.Run("exec deletes", func(t *testing.T) {
err := testClient.ExecuteStateTransaction(ctx, store, meta, adds)
assert.Nil(t, err)
require.NoError(t, err)
})
t.Run("ensure deletes", func(t *testing.T) {
items, err := testClient.GetBulkState(ctx, store, keys, nil, 3)
assert.Nil(t, err)
require.NoError(t, err)
assert.NotNil(t, items)
assert.Len(t, items, 0)
assert.Empty(t, items)
})
}
func TestQueryState(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
data := testData
store := testStore
key1 := "key1"
@ -357,28 +417,39 @@ func TestQueryState(t *testing.T) {
t.Run("save data", func(t *testing.T) {
err := testClient.SaveState(ctx, store, key1, []byte(data), nil)
assert.NoError(t, err)
require.NoError(t, err)
err = testClient.SaveState(ctx, store, key2, []byte(data), nil)
assert.NoError(t, err)
require.NoError(t, err)
})
t.Run("error query", func(t *testing.T) {
_, err := testClient.QueryStateAlpha1(ctx, "", "", nil)
assert.Error(t, err)
require.Error(t, err)
_, err = testClient.QueryStateAlpha1(ctx, store, "", nil)
assert.Error(t, err)
require.Error(t, err)
_, err = testClient.QueryStateAlpha1(ctx, store, "bad syntax", nil)
assert.Error(t, err)
require.Error(t, err)
})
t.Run("query data", func(t *testing.T) {
query := `{}`
resp, err := testClient.QueryStateAlpha1(ctx, store, query, nil)
assert.NoError(t, err)
assert.Equal(t, 2, len(resp.Results))
require.NoError(t, err)
assert.Len(t, resp.Results, 2)
for _, item := range resp.Results {
assert.True(t, item.Key == key1 || item.Key == key2)
assert.Equal(t, []byte(data), item.Value)
}
})
}
func TestHasRequiredStateArgs(t *testing.T) {
t.Run("empty store should error", func(t *testing.T) {
err := hasRequiredStateArgs("", "key")
require.Error(t, err)
})
t.Run("empty key should error", func(t *testing.T) {
err := hasRequiredStateArgs("storeName", "")
require.Error(t, err)
})
}

299
client/subscribe.go Normal file
View File

@ -0,0 +1,299 @@
/*
Copyright 2024 The Dapr Authors
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 client
import (
"context"
"encoding/json"
"errors"
"fmt"
"mime"
"strings"
"sync"
"sync/atomic"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
pb "github.com/dapr/dapr/pkg/proto/runtime/v1"
"github.com/dapr/go-sdk/service/common"
)
type SubscriptionHandleFunction func(event *common.TopicEvent) common.SubscriptionResponseStatus
type SubscriptionOptions struct {
PubsubName string
Topic string
DeadLetterTopic *string
Metadata map[string]string
}
type Subscription struct {
ctx context.Context
stream pb.Dapr_SubscribeTopicEventsAlpha1Client
// lock locks concurrent writes to subscription stream.
lock sync.Mutex
closed atomic.Bool
createStream func(ctx context.Context, opts SubscriptionOptions) (pb.Dapr_SubscribeTopicEventsAlpha1Client, error)
opts SubscriptionOptions
}
type SubscriptionMessage struct {
*common.TopicEvent
sub *Subscription
}
func (c *GRPCClient) Subscribe(ctx context.Context, opts SubscriptionOptions) (*Subscription, error) {
stream, err := c.subscribeInitialRequest(ctx, opts)
if err != nil {
return nil, err
}
s := &Subscription{
ctx: ctx,
stream: stream,
createStream: c.subscribeInitialRequest,
opts: opts,
}
return s, nil
}
func (c *GRPCClient) SubscribeWithHandler(ctx context.Context, opts SubscriptionOptions, handler SubscriptionHandleFunction) (func() error, error) {
s, err := c.Subscribe(ctx, opts)
if err != nil {
return nil, err
}
go func() {
defer s.Close()
for {
msg, err := s.Receive()
if err != nil {
if !s.closed.Load() {
logger.Printf("Error receiving messages from subscription pubsub=%s topic=%s, closing subscription: %s",
opts.PubsubName, opts.Topic, err)
}
return
}
go func() {
if err := msg.respondStatus(handler(msg.TopicEvent)); err != nil {
logger.Printf("Error responding to topic with event status pubsub=%s topic=%s message_id=%s: %s",
opts.PubsubName, opts.Topic, msg.ID, err)
}
}()
}
}()
return s.Close, nil
}
func (s *Subscription) Close() error {
if !s.closed.CompareAndSwap(false, true) {
return errors.New("subscription already closed")
}
return s.stream.CloseSend()
}
func (s *Subscription) Receive() (*SubscriptionMessage, error) {
for {
resp, err := s.stream.Recv()
if err != nil {
select {
case <-s.ctx.Done():
return nil, errors.New("subscription context closed")
default:
// proceed to check the gRPC status error
}
st, ok := status.FromError(err)
if !ok {
// not a grpc status error
return nil, err
}
switch st.Code() {
case codes.Unavailable, codes.Unknown:
logger.Printf("gRPC error while reading from stream: %s (code=%v)",
st.Message(), st.Code())
// close the current stream and reconnect
if s.closed.Load() {
return nil, errors.New("subscription is permanently closed; cannot reconnect")
}
if err := s.closeStreamOnly(); err != nil {
logger.Printf("error closing current stream: %v", err)
}
newStream, nerr := s.createStream(s.ctx, s.opts)
if nerr != nil {
return nil, errors.New("re-subscribe failed")
}
s.lock.Lock()
s.stream = newStream
s.lock.Unlock()
// try receiving again
continue
case codes.Canceled:
return nil, errors.New("stream canceled")
default:
return nil, errors.New("subscription recv error")
}
}
event := resp.GetEventMessage()
data := any(event.GetData())
if len(event.GetData()) > 0 {
mediaType, _, err := mime.ParseMediaType(event.GetDataContentType())
if err == nil {
var v interface{}
switch mediaType {
case "application/json":
if err := json.Unmarshal(event.GetData(), &v); err == nil {
data = v
}
case "text/plain":
// Assume UTF-8 encoded string.
data = string(event.GetData())
default:
if strings.HasPrefix(mediaType, "application/") &&
strings.HasSuffix(mediaType, "+json") {
if err := json.Unmarshal(event.GetData(), &v); err == nil {
data = v
}
}
}
}
}
topicEvent := &common.TopicEvent{
ID: event.GetId(),
Source: event.GetSource(),
Type: event.GetType(),
SpecVersion: event.GetSpecVersion(),
DataContentType: event.GetDataContentType(),
Data: data,
RawData: event.GetData(),
Topic: event.GetTopic(),
PubsubName: event.GetPubsubName(),
}
return &SubscriptionMessage{
sub: s,
TopicEvent: topicEvent,
}, nil
}
}
func (s *SubscriptionMessage) Success() error {
return s.respond(pb.TopicEventResponse_SUCCESS)
}
func (s *SubscriptionMessage) Retry() error {
return s.respond(pb.TopicEventResponse_RETRY)
}
func (s *SubscriptionMessage) Drop() error {
return s.respond(pb.TopicEventResponse_DROP)
}
func (s *SubscriptionMessage) respondStatus(status common.SubscriptionResponseStatus) error {
var statuspb pb.TopicEventResponse_TopicEventResponseStatus
switch status {
case common.SubscriptionResponseStatusSuccess:
statuspb = pb.TopicEventResponse_SUCCESS
case common.SubscriptionResponseStatusRetry:
statuspb = pb.TopicEventResponse_RETRY
case common.SubscriptionResponseStatusDrop:
statuspb = pb.TopicEventResponse_DROP
default:
return fmt.Errorf("unknown status, expected one of %s, %s, %s: %s",
common.SubscriptionResponseStatusSuccess, common.SubscriptionResponseStatusRetry,
common.SubscriptionResponseStatusDrop, status)
}
return s.respond(statuspb)
}
func (s *SubscriptionMessage) respond(status pb.TopicEventResponse_TopicEventResponseStatus) error {
s.sub.lock.Lock()
defer s.sub.lock.Unlock()
return s.sub.stream.Send(&pb.SubscribeTopicEventsRequestAlpha1{
SubscribeTopicEventsRequestType: &pb.SubscribeTopicEventsRequestAlpha1_EventProcessed{
EventProcessed: &pb.SubscribeTopicEventsRequestProcessedAlpha1{
Id: s.ID,
Status: &pb.TopicEventResponse{Status: status},
},
},
})
}
func (c *GRPCClient) subscribeInitialRequest(ctx context.Context, opts SubscriptionOptions) (pb.Dapr_SubscribeTopicEventsAlpha1Client, error) {
if len(opts.PubsubName) == 0 {
return nil, errors.New("pubsub name required")
}
if len(opts.Topic) == 0 {
return nil, errors.New("topic required")
}
stream, err := c.protoClient.SubscribeTopicEventsAlpha1(ctx)
if err != nil {
return nil, err
}
err = stream.Send(&pb.SubscribeTopicEventsRequestAlpha1{
SubscribeTopicEventsRequestType: &pb.SubscribeTopicEventsRequestAlpha1_InitialRequest{
InitialRequest: &pb.SubscribeTopicEventsRequestInitialAlpha1{
PubsubName: opts.PubsubName, Topic: opts.Topic,
Metadata: opts.Metadata, DeadLetterTopic: opts.DeadLetterTopic,
},
},
})
if err != nil {
return nil, errors.Join(err, stream.CloseSend())
}
resp, err := stream.Recv()
if err != nil {
return nil, errors.Join(err, stream.CloseSend())
}
switch resp.GetSubscribeTopicEventsResponseType().(type) {
case *pb.SubscribeTopicEventsResponseAlpha1_InitialResponse:
default:
return nil, fmt.Errorf("unexpected initial response from server : %v", resp)
}
return stream, nil
}
func (s *Subscription) closeStreamOnly() error {
s.lock.Lock()
defer s.lock.Unlock()
if s.stream != nil {
return s.stream.CloseSend()
}
return nil
}

View File

@ -21,6 +21,8 @@ import (
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
@ -101,7 +103,7 @@ func createUnresponsiveServer(network string, unresponsiveServerAddress string)
}
func createNonBlockingClient(ctx context.Context, serverAddr string) (client Client, err error) {
conn, err := grpc.DialContext(
conn, err := grpc.DialContext( //nolint:staticcheck
ctx,
serverAddr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
@ -114,44 +116,44 @@ func createNonBlockingClient(ctx context.Context, serverAddr string) (client Cli
}
func TestGrpcWaitHappyCase(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
err := testClient.Wait(ctx, waitTimeout)
assert.NoError(t, err)
require.NoError(t, err)
}
func TestGrpcWaitUnresponsiveTcpServer(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
server, err := createUnresponsiveTCPServer()
assert.NoError(t, err)
require.NoError(t, err)
defer server.Close()
clientConnectionTimeoutCtx, cancel := context.WithTimeout(ctx, connectionTimeout)
defer cancel()
client, err := createNonBlockingClient(clientConnectionTimeoutCtx, server.address)
assert.NoError(t, err)
require.NoError(t, err)
err = client.Wait(ctx, waitTimeout)
assert.Error(t, err)
require.Error(t, err)
assert.Equal(t, errWaitTimedOut, err)
assert.GreaterOrEqual(t, atomic.LoadUint64(&server.nClientsSeen), uint64(1))
}
func TestGrpcWaitUnresponsiveUnixServer(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
server, err := createUnresponsiveUnixServer()
assert.NoError(t, err)
require.NoError(t, err)
defer server.Close()
clientConnectionTimeoutCtx, cancel := context.WithTimeout(ctx, connectionTimeout)
defer cancel()
client, err := createNonBlockingClient(clientConnectionTimeoutCtx, "unix://"+server.address)
assert.NoError(t, err)
require.NoError(t, err)
err = client.Wait(ctx, waitTimeout)
assert.Error(t, err)
require.Error(t, err)
assert.Equal(t, errWaitTimedOut, err)
assert.GreaterOrEqual(t, atomic.LoadUint64(&server.nClientsSeen), uint64(1))
}

268
client/workflow.go Normal file
View File

@ -0,0 +1,268 @@
/*
Copyright 2024 The Dapr Authors
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 client
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
"github.com/google/uuid"
pb "github.com/dapr/dapr/pkg/proto/runtime/v1"
)
const (
DefaultWorkflowComponent = "dapr"
)
type StartWorkflowRequest struct {
InstanceID string // Optional instance identifier
WorkflowComponent string
WorkflowName string
Options map[string]string // Optional metadata
Input any // Optional input
SendRawInput bool // Set to True in order to disable serialization on the input
}
type StartWorkflowResponse struct {
InstanceID string
}
type GetWorkflowRequest struct {
InstanceID string
WorkflowComponent string
}
type GetWorkflowResponse struct {
InstanceID string
WorkflowName string
CreatedAt time.Time
LastUpdatedAt time.Time
RuntimeStatus string
Properties map[string]string
}
type PurgeWorkflowRequest struct {
InstanceID string
WorkflowComponent string
}
type TerminateWorkflowRequest struct {
InstanceID string
WorkflowComponent string
}
type PauseWorkflowRequest struct {
InstanceID string
WorkflowComponent string
}
type ResumeWorkflowRequest struct {
InstanceID string
WorkflowComponent string
}
type RaiseEventWorkflowRequest struct {
InstanceID string
WorkflowComponent string
EventName string
EventData any
SendRawData bool // Set to True in order to disable serialization on the data
}
// StartWorkflowBeta1 starts a workflow using the beta1 spec.
func (c *GRPCClient) StartWorkflowBeta1(ctx context.Context, req *StartWorkflowRequest) (*StartWorkflowResponse, error) {
if req.InstanceID == "" {
req.InstanceID = uuid.New().String()
}
if req.WorkflowComponent == "" {
req.WorkflowComponent = DefaultWorkflowComponent
}
if req.WorkflowName == "" {
return nil, errors.New("failed to start workflow: WorkflowName must be supplied")
}
var input []byte
var err error
if req.SendRawInput {
var ok bool
if input, ok = req.Input.([]byte); !ok {
return nil, errors.New("failed to start workflow: sendrawinput is true however, input is not a byte slice")
}
} else {
input, err = marshalInput(req.Input)
if err != nil {
return nil, fmt.Errorf("failed to start workflow: %v", err)
}
}
resp, err := c.protoClient.StartWorkflowBeta1(ctx, &pb.StartWorkflowRequest{
InstanceId: req.InstanceID,
WorkflowComponent: req.WorkflowComponent,
WorkflowName: req.WorkflowName,
Options: req.Options,
Input: input,
})
if err != nil {
return nil, fmt.Errorf("failed to start workflow instance: %v", err)
}
return &StartWorkflowResponse{
InstanceID: resp.GetInstanceId(),
}, nil
}
// GetWorkflowBeta1 gets the status of a workflow using the beta1 spec.
func (c *GRPCClient) GetWorkflowBeta1(ctx context.Context, req *GetWorkflowRequest) (*GetWorkflowResponse, error) {
if req.InstanceID == "" {
return nil, errors.New("failed to get workflow status: InstanceID must be supplied")
}
if req.WorkflowComponent == "" {
req.WorkflowComponent = DefaultWorkflowComponent
}
resp, err := c.protoClient.GetWorkflowBeta1(ctx, &pb.GetWorkflowRequest{
InstanceId: req.InstanceID,
WorkflowComponent: req.WorkflowComponent,
})
if err != nil {
return nil, fmt.Errorf("failed to get workflow status: %v", err)
}
return &GetWorkflowResponse{
InstanceID: resp.GetInstanceId(),
WorkflowName: resp.GetWorkflowName(),
CreatedAt: resp.GetCreatedAt().AsTime(),
LastUpdatedAt: resp.GetLastUpdatedAt().AsTime(),
RuntimeStatus: resp.GetRuntimeStatus(),
Properties: resp.GetProperties(),
}, nil
}
// PurgeWorkflowBeta1 removes all metadata relating to a specific workflow using the beta1 spec.
func (c *GRPCClient) PurgeWorkflowBeta1(ctx context.Context, req *PurgeWorkflowRequest) error {
if req.InstanceID == "" {
return errors.New("failed to purge workflow: InstanceID must be supplied")
}
if req.WorkflowComponent == "" {
req.WorkflowComponent = DefaultWorkflowComponent
}
_, err := c.protoClient.PurgeWorkflowBeta1(ctx, &pb.PurgeWorkflowRequest{
InstanceId: req.InstanceID,
WorkflowComponent: req.WorkflowComponent,
})
if err != nil {
return fmt.Errorf("failed to purge workflow: %v", err)
}
return nil
}
// TerminateWorkflowBeta1 stops a workflow using the beta1 spec.
func (c *GRPCClient) TerminateWorkflowBeta1(ctx context.Context, req *TerminateWorkflowRequest) error {
if req.InstanceID == "" {
return errors.New("failed to terminate workflow: InstanceID must be supplied")
}
if req.WorkflowComponent == "" {
req.WorkflowComponent = DefaultWorkflowComponent
}
_, err := c.protoClient.TerminateWorkflowBeta1(ctx, &pb.TerminateWorkflowRequest{
InstanceId: req.InstanceID,
WorkflowComponent: req.WorkflowComponent,
})
if err != nil {
return fmt.Errorf("failed to terminate workflow: %v", err)
}
return nil
}
// PauseWorkflowBeta1 pauses a workflow that can be resumed later using the beta1 spec.
func (c *GRPCClient) PauseWorkflowBeta1(ctx context.Context, req *PauseWorkflowRequest) error {
if req.InstanceID == "" {
return errors.New("failed to pause workflow: InstanceID must be supplied")
}
if req.WorkflowComponent == "" {
req.WorkflowComponent = DefaultWorkflowComponent
}
_, err := c.protoClient.PauseWorkflowBeta1(ctx, &pb.PauseWorkflowRequest{
InstanceId: req.InstanceID,
WorkflowComponent: req.WorkflowComponent,
})
if err != nil {
return fmt.Errorf("failed to pause workflow: %v", err)
}
return nil
}
// ResumeWorkflowBeta1 resumes a paused workflow using the beta1 spec.
func (c *GRPCClient) ResumeWorkflowBeta1(ctx context.Context, req *ResumeWorkflowRequest) error {
if req.InstanceID == "" {
return errors.New("failed to resume workflow: InstanceID must be supplied")
}
if req.WorkflowComponent == "" {
req.WorkflowComponent = DefaultWorkflowComponent
}
_, err := c.protoClient.ResumeWorkflowBeta1(ctx, &pb.ResumeWorkflowRequest{
InstanceId: req.InstanceID,
WorkflowComponent: req.WorkflowComponent,
})
if err != nil {
return fmt.Errorf("failed to resume workflow: %v", err)
}
return nil
}
// RaiseEventWorkflowBeta1 raises an event on a workflow using the beta1 spec.
func (c *GRPCClient) RaiseEventWorkflowBeta1(ctx context.Context, req *RaiseEventWorkflowRequest) error {
if req.InstanceID == "" {
return errors.New("failed to raise event on workflow: InstanceID must be supplied")
}
if req.WorkflowComponent == "" {
req.WorkflowComponent = DefaultWorkflowComponent
}
if req.EventName == "" {
return errors.New("failed to raise event on workflow: EventName must be supplied")
}
var eventData []byte
var err error
if req.SendRawData {
var ok bool
if eventData, ok = req.EventData.([]byte); !ok {
return errors.New("failed to raise event on workflow: SendRawData is true however, eventData is not a byte slice")
}
} else {
eventData, err = marshalInput(req.EventData)
if err != nil {
return fmt.Errorf("failed to raise an event on workflow: %v", err)
}
}
_, err = c.protoClient.RaiseEventWorkflowBeta1(ctx, &pb.RaiseEventWorkflowRequest{
InstanceId: req.InstanceID,
WorkflowComponent: req.WorkflowComponent,
EventName: req.EventName,
EventData: eventData,
})
if err != nil {
return fmt.Errorf("failed to raise event on workflow: %v", err)
}
return nil
}
func marshalInput(input any) (data []byte, err error) {
if input == nil {
return nil, nil
}
return json.Marshal(input)
}

374
client/workflow_test.go Normal file
View File

@ -0,0 +1,374 @@
/*
Copyright 2024 The Dapr Authors
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 client
import (
"math"
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"
)
func TestMarshalInput(t *testing.T) {
var input any
t.Run("string", func(t *testing.T) {
input = "testString"
data, err := marshalInput(input)
require.NoError(t, err)
assert.Equal(t, []byte{0x22, 0x74, 0x65, 0x73, 0x74, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22}, data)
})
}
func TestWorkflowBeta1(t *testing.T) {
ctx := t.Context()
// 1: StartWorkflow
t.Run("start workflow - valid (without id)", func(t *testing.T) {
resp, err := testClient.StartWorkflowBeta1(ctx, &StartWorkflowRequest{
InstanceID: "",
WorkflowComponent: "dapr",
WorkflowName: "TestWorkflow",
})
require.NoError(t, err)
assert.NotNil(t, resp.InstanceID)
})
t.Run("start workflow - valid (with id)", func(t *testing.T) {
resp, err := testClient.StartWorkflowBeta1(ctx, &StartWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "dapr",
WorkflowName: "TestWorkflow",
})
require.NoError(t, err)
assert.Equal(t, "TestID", resp.InstanceID)
})
t.Run("start workflow - valid (without component name)", func(t *testing.T) {
resp, err := testClient.StartWorkflowBeta1(ctx, &StartWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "",
WorkflowName: "TestWorkflow",
})
require.NoError(t, err)
assert.Equal(t, "TestID", resp.InstanceID)
})
t.Run("start workflow - rpc failure", func(t *testing.T) {
resp, err := testClient.StartWorkflowBeta1(ctx, &StartWorkflowRequest{
InstanceID: testWorkflowFailureID,
WorkflowComponent: "dapr",
WorkflowName: "TestWorkflow",
})
require.Error(t, err)
assert.Nil(t, resp)
})
t.Run("start workflow - grpc failure", func(t *testing.T) {
resp, err := testClient.StartWorkflowBeta1(ctx, &StartWorkflowRequest{
InstanceID: "",
WorkflowComponent: "dapr",
WorkflowName: "",
})
require.Error(t, err)
assert.Nil(t, resp)
})
t.Run("start workflow - cannot serialize input", func(t *testing.T) {
resp, err := testClient.StartWorkflowBeta1(ctx, &StartWorkflowRequest{
InstanceID: "",
WorkflowComponent: "dapr",
WorkflowName: "TestWorkflow",
Input: math.NaN(),
SendRawInput: false,
})
require.Error(t, err)
assert.Nil(t, resp)
})
t.Run("start workflow - raw input", func(t *testing.T) {
resp, err := testClient.StartWorkflowBeta1(ctx, &StartWorkflowRequest{
InstanceID: "",
WorkflowComponent: "dapr",
WorkflowName: "TestWorkflow",
Input: []byte("stringtest"),
SendRawInput: true,
})
require.NoError(t, err)
assert.NotNil(t, resp)
})
t.Run("start workflow - raw input (invalid)", func(t *testing.T) {
resp, err := testClient.StartWorkflowBeta1(ctx, &StartWorkflowRequest{
InstanceID: "",
WorkflowComponent: "dapr",
WorkflowName: "TestWorkflow",
Input: "test string",
SendRawInput: true,
})
require.Error(t, err)
assert.Nil(t, resp)
})
// 2: GetWorkflow
t.Run("get workflow", func(t *testing.T) {
resp, err := testClient.GetWorkflowBeta1(ctx, &GetWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "dapr",
})
require.NoError(t, err)
assert.NotNil(t, resp)
})
t.Run("get workflow - valid", func(t *testing.T) {
resp, err := testClient.GetWorkflowBeta1(ctx, &GetWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "dapr",
})
require.NoError(t, err)
assert.NotNil(t, resp)
})
t.Run("get workflow - valid (without component)", func(t *testing.T) {
resp, err := testClient.GetWorkflowBeta1(ctx, &GetWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "",
})
require.NoError(t, err)
assert.NotNil(t, resp)
})
t.Run("get workflow - invalid id", func(t *testing.T) {
resp, err := testClient.GetWorkflowBeta1(ctx, &GetWorkflowRequest{
InstanceID: "",
WorkflowComponent: "dapr",
})
require.Error(t, err)
assert.Nil(t, resp)
})
t.Run("get workflow - grpc fail", func(t *testing.T) {
resp, err := testClient.GetWorkflowBeta1(ctx, &GetWorkflowRequest{
InstanceID: testWorkflowFailureID,
WorkflowComponent: "dapr",
})
require.Error(t, err)
assert.Nil(t, resp)
})
// 3: PauseWorkflow
t.Run("pause workflow", func(t *testing.T) {
err := testClient.PauseWorkflowBeta1(ctx, &PauseWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "dapr",
})
require.NoError(t, err)
})
t.Run("pause workflow - valid (without component)", func(t *testing.T) {
err := testClient.PauseWorkflowBeta1(ctx, &PauseWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "",
})
require.NoError(t, err)
})
t.Run("pause workflow invalid instanceid", func(t *testing.T) {
err := testClient.PauseWorkflowBeta1(ctx, &PauseWorkflowRequest{
InstanceID: "",
WorkflowComponent: "dapr",
})
require.Error(t, err)
})
t.Run("pause workflow", func(t *testing.T) {
err := testClient.PauseWorkflowBeta1(ctx, &PauseWorkflowRequest{
InstanceID: testWorkflowFailureID,
WorkflowComponent: "dapr",
})
require.Error(t, err)
})
// 4: ResumeWorkflow
t.Run("resume workflow", func(t *testing.T) {
err := testClient.ResumeWorkflowBeta1(ctx, &ResumeWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "dapr",
})
require.NoError(t, err)
})
t.Run("resume workflow - valid (without component)", func(t *testing.T) {
err := testClient.ResumeWorkflowBeta1(ctx, &ResumeWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "",
})
require.NoError(t, err)
})
t.Run("resume workflow - invalid instanceid", func(t *testing.T) {
err := testClient.ResumeWorkflowBeta1(ctx, &ResumeWorkflowRequest{
InstanceID: "",
WorkflowComponent: "dapr",
})
require.Error(t, err)
})
t.Run("resume workflow - grpc fail", func(t *testing.T) {
err := testClient.ResumeWorkflowBeta1(ctx, &ResumeWorkflowRequest{
InstanceID: testWorkflowFailureID,
WorkflowComponent: "dapr",
})
require.Error(t, err)
})
// 5: TerminateWorkflow
t.Run("terminate workflow", func(t *testing.T) {
err := testClient.TerminateWorkflowBeta1(ctx, &TerminateWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "dapr",
})
require.NoError(t, err)
})
t.Run("terminate workflow - valid (without component)", func(t *testing.T) {
err := testClient.TerminateWorkflowBeta1(ctx, &TerminateWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "",
})
require.NoError(t, err)
})
t.Run("terminate workflow - invalid instanceid", func(t *testing.T) {
err := testClient.TerminateWorkflowBeta1(ctx, &TerminateWorkflowRequest{
InstanceID: "",
WorkflowComponent: "dapr",
})
require.Error(t, err)
})
t.Run("terminate workflow - grpc failure", func(t *testing.T) {
err := testClient.TerminateWorkflowBeta1(ctx, &TerminateWorkflowRequest{
InstanceID: testWorkflowFailureID,
WorkflowComponent: "dapr",
})
require.Error(t, err)
})
// 6: RaiseEventWorkflow
t.Run("raise event workflow", func(t *testing.T) {
err := testClient.RaiseEventWorkflowBeta1(ctx, &RaiseEventWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "dapr",
EventName: "TestEvent",
})
require.NoError(t, err)
})
t.Run("raise event workflow - valid (without component)", func(t *testing.T) {
err := testClient.RaiseEventWorkflowBeta1(ctx, &RaiseEventWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "",
EventName: "TestEvent",
})
require.NoError(t, err)
})
t.Run("raise event workflow - invalid instanceid", func(t *testing.T) {
err := testClient.RaiseEventWorkflowBeta1(ctx, &RaiseEventWorkflowRequest{
InstanceID: "",
WorkflowComponent: "dapr",
EventName: "TestEvent",
})
require.Error(t, err)
})
t.Run("raise event workflow - invalid eventname", func(t *testing.T) {
err := testClient.RaiseEventWorkflowBeta1(ctx, &RaiseEventWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "dapr",
EventName: "",
})
require.Error(t, err)
})
t.Run("raise event workflow - grpc failure", func(t *testing.T) {
err := testClient.RaiseEventWorkflowBeta1(ctx, &RaiseEventWorkflowRequest{
InstanceID: testWorkflowFailureID,
WorkflowComponent: "dapr",
EventName: "TestEvent",
})
require.Error(t, err)
})
t.Run("raise event workflow - cannot serialize input", func(t *testing.T) {
err := testClient.RaiseEventWorkflowBeta1(ctx, &RaiseEventWorkflowRequest{
InstanceID: testWorkflowFailureID,
WorkflowComponent: "dapr",
EventName: "TestEvent",
EventData: math.NaN(),
SendRawData: false,
})
require.Error(t, err)
})
t.Run("raise event workflow - raw input", func(t *testing.T) {
err := testClient.RaiseEventWorkflowBeta1(ctx, &RaiseEventWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "dapr",
EventName: "TestEvent",
EventData: []byte("teststring"),
SendRawData: true,
})
require.NoError(t, err)
})
t.Run("raise event workflow - raw input (invalid)", func(t *testing.T) {
err := testClient.RaiseEventWorkflowBeta1(ctx, &RaiseEventWorkflowRequest{
InstanceID: testWorkflowFailureID,
WorkflowComponent: "dapr",
EventName: "TestEvent",
EventData: "test string",
SendRawData: true,
})
require.Error(t, err)
})
// 7: PurgeWorkflow
t.Run("purge workflow", func(t *testing.T) {
err := testClient.PurgeWorkflowBeta1(ctx, &PurgeWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "dapr",
})
require.NoError(t, err)
})
t.Run("purge workflow - valid (without component)", func(t *testing.T) {
err := testClient.PurgeWorkflowBeta1(ctx, &PurgeWorkflowRequest{
InstanceID: "TestID",
WorkflowComponent: "",
})
require.NoError(t, err)
})
t.Run("purge workflow - invalid instanceid", func(t *testing.T) {
err := testClient.PurgeWorkflowBeta1(ctx, &PurgeWorkflowRequest{
InstanceID: "",
WorkflowComponent: "dapr",
})
require.Error(t, err)
})
t.Run("purge workflow - grpc failure", func(t *testing.T) {
err := testClient.PurgeWorkflowBeta1(ctx, &PurgeWorkflowRequest{
InstanceID: testWorkflowFailureID,
WorkflowComponent: "dapr",
})
require.Error(t, err)
})
}

View File

@ -20,6 +20,48 @@ The Dapr client package allows you to interact with other Dapr applications from
```go
import "github.com/dapr/go-sdk/client"
```
## Error handling
Dapr errors are based on [gRPC's richer error model](https://cloud.google.com/apis/design/errors#error_model).
The following code shows an example of how you can parse and handle the error details:
```go
if err != nil {
st := status.Convert(err)
fmt.Printf("Code: %s\n", st.Code().String())
fmt.Printf("Message: %s\n", st.Message())
for _, detail := range st.Details() {
switch t := detail.(type) {
case *errdetails.ErrorInfo:
// Handle ErrorInfo details
fmt.Printf("ErrorInfo:\n- Domain: %s\n- Reason: %s\n- Metadata: %v\n", t.GetDomain(), t.GetReason(), t.GetMetadata())
case *errdetails.BadRequest:
// Handle BadRequest details
fmt.Println("BadRequest:")
for _, violation := range t.GetFieldViolations() {
fmt.Printf("- Key: %s\n", violation.GetField())
fmt.Printf("- The %q field was wrong: %s\n", violation.GetField(), violation.GetDescription())
}
case *errdetails.ResourceInfo:
// Handle ResourceInfo details
fmt.Printf("ResourceInfo:\n- Resource type: %s\n- Resource name: %s\n- Owner: %s\n- Description: %s\n",
t.GetResourceType(), t.GetResourceName(), t.GetOwner(), t.GetDescription())
case *errdetails.Help:
// Handle ResourceInfo details
fmt.Println("HelpInfo:")
for _, link := range t.GetLinks() {
fmt.Printf("- Url: %s\n", link.Url)
fmt.Printf("- Description: %s\n", link.Description)
}
default:
// Add cases for other types of details you expect
fmt.Printf("Unhandled error detail type: %v\n", t)
}
}
}
```
## Building blocks
@ -46,6 +88,91 @@ resp, err = client.InvokeMethodWithContent(ctx, "app-id", "method-name", "post",
For a full guide on service invocation, visit [How-To: Invoke a service]({{< ref howto-invoke-discover-services.md >}}).
### Workflows
Workflows and their activities can be authored and managed using the Dapr Go SDK like so:
```go
import (
...
"github.com/dapr/go-sdk/workflow"
...
)
func ExampleWorkflow(ctx *workflow.WorkflowContext) (any, error) {
var output string
input := "world"
if err := ctx.CallActivity(ExampleActivity, workflow.ActivityInput(input)).Await(&output); err != nil {
return nil, err
}
// Print output - "hello world"
fmt.Println(output)
return nil, nil
}
func ExampleActivity(ctx workflow.ActivityContext) (any, error) {
var input int
if err := ctx.GetInput(&input); err != nil {
return "", err
}
return fmt.Sprintf("hello %s", input), nil
}
func main() {
// Create a workflow worker
w, err := workflow.NewWorker()
if err != nil {
log.Fatalf("error creating worker: %v", err)
}
// Register the workflow
w.RegisterWorkflow(ExampleWorkflow)
// Register the activity
w.RegisterActivity(ExampleActivity)
// Start workflow runner
if err := w.Start(); err != nil {
log.Fatal(err)
}
// Create a workflow client
wfClient, err := workflow.NewClient()
if err != nil {
log.Fatal(err)
}
// Start a new workflow
id, err := wfClient.ScheduleNewWorkflow(context.Background(), "ExampleWorkflow")
if err != nil {
log.Fatal(err)
}
// Wait for the workflow to complete
metadata, err := wfClient.WaitForWorkflowCompletion(ctx, id)
if err != nil {
log.Fatal(err)
}
// Print workflow status post-completion
fmt.Println(metadata.RuntimeStatus)
// Shutdown Worker
w.Shutdown()
}
```
- For a more comprehensive guide on workflows visit these How-To guides:
- [How-To: Author a workflow]({{< ref howto-author-workflow.md >}}).
- [How-To: Manage a workflow]({{< ref howto-manage-workflow.md >}}).
- Visit the Go SDK Examples to jump into complete examples:
- [Workflow Example](https://github.com/dapr/go-sdk/tree/main/examples/workflow)
- [Workflow - Parallelised](https://github.com/dapr/go-sdk/tree/main/examples/workflow-parallel)
### State Management
For simple use-cases, Dapr client provides easy to use `Save`, `Get`, `Delete` methods:
@ -203,6 +330,49 @@ if res.Error != nil {
For a full guide on pub/sub, visit [How-To: Publish & subscribe]({{< ref howto-publish-subscribe.md >}}).
### Workflow
You can create [workflows]({{< ref workflow-overview.md >}}) using the Go SDK. For example, start with a simple workflow activity:
```go
func TestActivity(ctx workflow.ActivityContext) (any, error) {
var input int
if err := ctx.GetInput(&input); err != nil {
return "", err
}
// Do something here
return "result", nil
}
```
Write a simple workflow function:
```go
func TestWorkflow(ctx *workflow.WorkflowContext) (any, error) {
var input int
if err := ctx.GetInput(&input); err != nil {
return nil, err
}
var output string
if err := ctx.CallActivity(TestActivity, workflow.ActivityInput(input)).Await(&output); err != nil {
return nil, err
}
if err := ctx.WaitForExternalEvent("testEvent", time.Second*60).Await(&output); err != nil {
return nil, err
}
if err := ctx.CreateTimer(time.Second).Await(nil); err != nil {
return nil, nil
}
return output, nil
}
```
Then compose your application that will use the workflow you've created. [Refer to the How-To: Author workflows guide]({{< ref howto-author-workflow.md >}}) for a full walk-through.
Try out the [Go SDK workflow example.](https://github.com/dapr/go-sdk/blob/main/examples/workflow)
### Output Bindings
@ -304,7 +474,7 @@ opt := map[string]string{
secret, err := client.GetSecret(ctx, "store-name", "secret-name", opt)
```
#### Authentication
### Authentication
By default, Dapr relies on the network boundary to limit access to its API. If however the target Dapr API is configured with token-based authentication, users can configure the Go Dapr client with that token in two ways:
@ -404,7 +574,7 @@ To encrypt:
```go
// Encrypt the data using Dapr
out, err := sdkClient.Encrypt(context.Background(), rf, dapr.EncryptOptions{
out, err := client.Encrypt(context.Background(), rf, dapr.EncryptOptions{
// These are the 3 required parameters
ComponentName: "mycryptocomponent",
KeyName: "mykey",
@ -419,7 +589,7 @@ To decrypt:
```go
// Decrypt the data using Dapr
out, err := sdkClient.Decrypt(context.Background(), rf, dapr.EncryptOptions{
out, err := client.Decrypt(context.Background(), rf, dapr.EncryptOptions{
// Only required option is the component name
ComponentName: "mycryptocomponent",
})
@ -428,4 +598,4 @@ out, err := sdkClient.Decrypt(context.Background(), rf, dapr.EncryptOptions{
For a full guide on cryptography, visit [How-To: Use the cryptography APIs]({{< ref howto-cryptography.md >}}).
## Related links
[Go SDK Examples](https://github.com/dapr/go-sdk/tree/main/examples)
[Go SDK Examples](https://github.com/dapr/go-sdk/tree/main/examples)

View File

@ -83,6 +83,35 @@ if err != nil {
}
```
You can also create a custom type that implements the `TopicEventSubscriber` interface to handle your events:
```go
type EventHandler struct {
// any data or references that your event handler needs.
}
func (h *EventHandler) Handle(ctx context.Context, e *common.TopicEvent) (retry bool, err error) {
log.Printf("event - PubsubName:%s, Topic:%s, ID:%s, Data: %v", e.PubsubName, e.Topic, e.ID, e.Data)
// do something with the event
return true, nil
}
```
The `EventHandler` can then be added using the `AddTopicEventSubscriber` method:
```go
sub := &common.Subscription{
PubsubName: "messages",
Topic: "topic1",
}
eventHandler := &EventHandler{
// initialize any fields
}
if err := s.AddTopicEventSubscriber(sub, eventHandler); err != nil {
log.Fatalf("error adding topic subscription: %v", err)
}
```
### Service Invocation Handler
To handle service invocations you will need to add at least one service invocation handler before starting the service:

View File

@ -78,6 +78,35 @@ if err != nil {
}
```
You can also create a custom type that implements the `TopicEventSubscriber` interface to handle your events:
```go
type EventHandler struct {
// any data or references that your event handler needs.
}
func (h *EventHandler) Handle(ctx context.Context, e *common.TopicEvent) (retry bool, err error) {
log.Printf("event - PubsubName:%s, Topic:%s, ID:%s, Data: %v", e.PubsubName, e.Topic, e.ID, e.Data)
// do something with the event
return true, nil
}
```
The `EventHandler` can then be added using the `AddTopicEventSubscriber` method:
```go
sub := &common.Subscription{
PubsubName: "messages",
Topic: "topic1",
}
eventHandler := &EventHandler{
// initialize any fields
}
if err := s.AddTopicEventSubscriber(sub, eventHandler); err != nil {
log.Fatalf("error adding topic subscription: %v", err)
}
```
### Service Invocation Handler
To handle service invocations you will need to add at least one service invocation handler before starting the service:

View File

@ -17,10 +17,11 @@ expected_stdout_lines:
- '== APP == get post request = laurence'
- '== APP == get req = hello'
- '== APP == get req = hello'
- '== APP == receive reminder = testReminderName state = "hello" duetime = 5s period = 5s'
- '== APP == receive reminder = testReminderName state = "hello" duetime = 5s period = 5s'
- '== APP == receive reminder = testReminderName state = "hello"'
- '== APP == receive reminder = testReminderName state = "hello"'
background: true
sleep: 30
timeout_seconds: 60
-->
```bash
@ -54,6 +55,7 @@ expected_stdout_lines:
background: true
sleep: 40
timeout_seconds: 60
-->
```bash
@ -67,20 +69,11 @@ dapr run --app-id actor-client \
### Cleanup
<!-- STEP
expected_stdout_lines:
- '✅ app stopped successfully: actor-serving'
expected_stderr_lines:
name: Shutdown dapr
-->
```bash
dapr stop --app-id actor-serving
(lsof -i:8080 | grep main) | awk '{print $2}' | xargs kill
```
<!-- END_STEP -->
## Result
- client side
```
@ -106,6 +99,6 @@ dapr stop --app-id actor-serving
== APP == get post request = laurence
== APP == get req = hello
== APP == get req = hello
== APP == receive reminder = testReminderName state = "hello" duetime = 5s period = 5s
== APP == receive reminder = testReminderName state = "hello" duetime = 5s period = 5s
```
== APP == receive reminder = testReminderName state = "hello"
== APP == receive reminder = testReminderName state = "hello"
```

View File

@ -1,24 +0,0 @@
module github.com/dapr/go-sdk/examples/actor
go 1.19
// Needed to validate SDK changes in CI/CD
replace github.com/dapr/go-sdk => ../../
require (
github.com/dapr/go-sdk v0.0.0-00010101000000-000000000000
github.com/google/uuid v1.3.0
)
require (
github.com/go-chi/chi/v5 v5.0.8 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/kr/pretty v0.3.1 // indirect
golang.org/x/net v0.5.0 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/text v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf // indirect
google.golang.org/grpc v1.51.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,40 +0,0 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf h1:/JqRexUvugu6JURQ0O7RfV1EnvgrOxUV4tSjuAv0Sr0=
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -124,7 +124,7 @@ func (t *TestActor) IncrementAndGet(ctx context.Context, stateKey string) (*api.
}
func (t *TestActor) ReminderCall(reminderName string, state []byte, dueTime string, period string) {
fmt.Println("receive reminder = ", reminderName, " state = ", string(state), "duetime = ", dueTime, "period = ", period)
fmt.Println("receive reminder = ", reminderName, " state = ", string(state))
}
func main() {

View File

@ -13,19 +13,20 @@ name: Run Configuration Client
output_match_mode: substring
match_order: none
expected_stdout_lines:
- '== APP == get config = myConfigValue'
- '== APP == get updated config key = mySubscribeKey1, value = mySubscribeValue1'
- '== APP == get updated config key = mySubscribeKey2, value = mySubscribeValue1'
- '== APP == get updated config key = mySubscribeKey3, value = mySubscribeValue1'
- '== APP == get updated config key = mySubscribeKey1, value = mySubscribeValue2'
- '== APP == get updated config key = mySubscribeKey2, value = mySubscribeValue2'
- '== APP == get updated config key = mySubscribeKey3, value = mySubscribeValue2'
- '== APP == get updated config key = mySubscribeKey1, value = mySubscribeValue3'
- '== APP == get updated config key = mySubscribeKey2, value = mySubscribeValue3'
- '== APP == get updated config key = mySubscribeKey3, value = mySubscribeValue3'
- '== APP == got config key = mykey, value = myConfigValue'
- '== APP == got config key = mySubscribeKey1, value = mySubscribeValue1'
- '== APP == got config key = mySubscribeKey2, value = mySubscribeValue1'
- '== APP == got config key = mySubscribeKey3, value = mySubscribeValue1'
- '== APP == got config key = mySubscribeKey1, value = mySubscribeValue2'
- '== APP == got config key = mySubscribeKey2, value = mySubscribeValue2'
- '== APP == got config key = mySubscribeKey3, value = mySubscribeValue2'
- '== APP == got config key = mySubscribeKey1, value = mySubscribeValue3'
- '== APP == got config key = mySubscribeKey2, value = mySubscribeValue3'
- '== APP == got config key = mySubscribeKey3, value = mySubscribeValue3'
- '== APP == dapr configuration subscribe finished.'
background: false
sleep: 40
timeout_seconds: 60
-->
```bash
@ -47,17 +48,25 @@ dapr run --app-id configuration-api\
The subscription event order may out of order.
```
get config = myConfigValue
get updated config key = mySubscribeKey1, value = mySubscribeValue1
get updated config key = mySubscribeKey2, value = mySubscribeValue1
get updated config key = mySubscribeKey3, value = mySubscribeValue1
get updated config key = mySubscribeKey1, value = mySubscribeValue2
get updated config key = mySubscribeKey2, value = mySubscribeValue2
get updated config key = mySubscribeKey3, value = mySubscribeValue2
get updated config key = mySubscribeKey1, value = mySubscribeValue3
get updated config key = mySubscribeKey2, value = mySubscribeValue3
get updated config key = mySubscribeKey3, value = mySubscribeValue3
got config key = mykey, value = myConfigValue
got config key = mySubscribeKey1, value = mySubscribeValue1
got config key = mySubscribeKey2, value = mySubscribeValue1
got config key = mySubscribeKey3, value = mySubscribeValue1
got config key = mySubscribeKey1, value = mySubscribeValue2
got config key = mySubscribeKey2, value = mySubscribeValue2
got config key = mySubscribeKey3, value = mySubscribeValue2
got config key = mySubscribeKey1, value = mySubscribeValue3
got config key = mySubscribeKey2, value = mySubscribeValue3
got config key = mySubscribeKey3, value = mySubscribeValue3
got config key = mySubscribeKey1, value = mySubscribeValue4
got config key = mySubscribeKey2, value = mySubscribeValue4
got config key = mySubscribeKey3, value = mySubscribeValue4
got config key = mySubscribeKey1, value = mySubscribeValue5
got config key = mySubscribeKey2, value = mySubscribeValue5
got config key = mySubscribeKey3, value = mySubscribeValue5
dapr configuration subscribe finished.
dapr configuration unsubscribed
✅ Exited App successfully
```

View File

@ -1,26 +0,0 @@
module github.com/dapr/go-sdk/examples/configuration
go 1.19
// Needed to validate SDK changes in CI/CD
replace github.com/dapr/go-sdk => ../../
require (
github.com/dapr/go-sdk v0.0.0-00010101000000-000000000000
github.com/go-redis/redis/v8 v8.11.5
google.golang.org/grpc v1.55.0
)
require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,49 +0,0 @@
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"strconv"
"sync"
"time"
dapr "github.com/dapr/go-sdk/client"
@ -11,7 +12,7 @@ import (
"google.golang.org/grpc/metadata"
)
func init() {
func addItems(wg *sync.WaitGroup) {
opts := &redis.Options{
Addr: "127.0.0.1:6379",
}
@ -19,10 +20,10 @@ func init() {
// set config value
client.Set(context.Background(), "mykey", "myConfigValue", -1)
ticker := time.NewTicker(time.Second)
wg.Add(3 * 5)
go func() {
for i := 0; i < 5; i++ {
<-ticker.C
// update config value
client.Set(context.Background(), "mySubscribeKey1", "mySubscribeValue"+strconv.Itoa(i+1), -1)
client.Set(context.Background(), "mySubscribeKey2", "mySubscribeValue"+strconv.Itoa(i+1), -1)
client.Set(context.Background(), "mySubscribeKey3", "mySubscribeValue"+strconv.Itoa(i+1), -1)
@ -32,6 +33,8 @@ func init() {
}
func main() {
var wg sync.WaitGroup
addItems(&wg)
ctx := context.Background()
client, err := dapr.NewClient()
if err != nil {
@ -42,25 +45,27 @@ func main() {
if err != nil {
panic(err)
}
fmt.Printf("get config = %s\n", (*items).Value)
fmt.Printf("got config key = mykey, value = %s \n", (*items).Value)
ctx, f := context.WithTimeout(ctx, 60*time.Second)
md := metadata.Pairs("dapr-app-id", "configuration-api")
ctx = metadata.NewOutgoingContext(ctx, md)
defer f()
subscribeID, err := client.SubscribeConfigurationItems(ctx, "example-config", []string{"mySubscribeKey1", "mySubscribeKey2", "mySubscribeKey3"}, func(id string, items map[string]*dapr.ConfigurationItem) {
wg.Done()
for k, v := range items {
fmt.Printf("get updated config key = %s, value = %s \n", k, v.Value)
fmt.Printf("got config key = %s, value = %s \n", k, v.Value)
}
})
if err != nil {
panic(err)
}
time.Sleep(time.Second*3 + time.Millisecond*500)
wg.Wait()
// dapr configuration unsubscribe called.
if err := client.UnsubscribeConfigurationItems(ctx, "example-config", subscribeID); err != nil {
panic(err)
}
time.Sleep(time.Second * 5)
fmt.Println("dapr configuration unsubscribed")
time.Sleep(time.Second)
}

View File

@ -0,0 +1,36 @@
# Dapr Conversation Example with go-sdk
## Step
### Prepare
- Dapr installed
### Run Conversation Example
<!-- STEP
name: Run Conversation
output_match_mode: substring
expected_stdout_lines:
- '== APP == conversation output: hello world'
background: true
sleep: 60
timeout_seconds: 60
-->
```bash
dapr run --app-id conversation \
--dapr-grpc-port 50001 \
--log-level debug \
--resources-path ./config \
-- go run ./main.go
```
<!-- END_STEP -->
## Result
```
- '== APP == conversation output: hello world'
```

View File

@ -0,0 +1,7 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: echo
spec:
type: conversation.echo
version: v1

View File

@ -0,0 +1,49 @@
/*
Copyright 2024 The Dapr Authors
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 main
import (
"context"
"fmt"
"log"
dapr "github.com/dapr/go-sdk/client"
)
func main() {
client, err := dapr.NewClient()
if err != nil {
panic(err)
}
input := dapr.ConversationInput{
Content: "hello world",
// Role: nil, // Optional
// ScrubPII: nil, // Optional
}
fmt.Printf("conversation input: %s\n", input.Content)
var conversationComponent = "echo"
request := dapr.NewConversationRequest(conversationComponent, []dapr.ConversationInput{input})
resp, err := client.ConverseAlpha1(context.Background(), request)
if err != nil {
log.Fatalf("err: %v", err)
}
fmt.Printf("conversation output: %s\n", resp.Outputs[0].Result)
}

74
examples/crypto/README.md Normal file
View File

@ -0,0 +1,74 @@
# Dapr Crypto Example with go-sdk
## Steps
### Prepare
- Dapr installed
> In order to run this sample, make sure that OpenSSL is available on your system.
### Running
1. This sample requires a private RSA key and a 256-bit symmetric (AES) key. We will generate them using OpenSSL:
<!-- STEP
name: Generate crypto
expected_stderr_lines:
output_match_mode: substring
background: false
sleep: 5
timeout_seconds: 30
-->
```bash
mkdir -p keys
# Generate a private RSA key, 4096-bit keys
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out keys/rsa-private-key.pem
# Generate a 256-bit key for AES
openssl rand -out keys/symmetric-key-256 32
```
<!-- END_STEP -->
2. Run the Go service app with Dapr:
<!-- STEP
name: Run crypto example
expected_stdout_lines:
- '== APP == Encrypted the message, got 856 bytes'
- '== APP == Decrypted the message, got 24 bytes'
- '== APP == The secret is "passw0rd"'
- '== APP == Wrote encrypted data to encrypted.out'
- '== APP == Wrote decrypted data to decrypted.out.jpg'
- "Exited App successfully"
expected_stderr_lines:
output_match_mode: substring
sleep: 30
timeout_seconds: 90
-->
```bash
dapr run --app-id crypto --resources-path ./components/ -- go run .
```
<!-- END_STEP -->
### Cleanup
`ctrl + c` to stop execution
```bash
dapr stop --app-id crypto
(lsof -i:8080 | grep crypto) | awk '{print $2}' | xargs kill
```
## Result
```shell
== APP == Encrypted the message, got 856 bytes
== APP == Decrypted the message, got 24 bytes
== APP == The secret is "passw0rd"
== APP == Wrote encrypted data to encrypted.out
== APP == Wrote decrypted data to decrypted.out.jpg
```

View File

@ -0,0 +1,11 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: localstorage
spec:
type: crypto.dapr.localstorage
version: v1
metadata:
- name: path
# Path is relative to the folder where the example is located
value: ./keys

BIN
examples/crypto/desert.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 MiB

162
examples/crypto/main.go Normal file
View File

@ -0,0 +1,162 @@
package main
import (
"bytes"
"context"
"fmt"
"io"
"log"
"os"
"strings"
dapr "github.com/dapr/go-sdk/client"
)
const (
// Name of the crypto component to use
CryptoComponentName = "localstorage"
// Name of the RSA private key to use
RSAKeyName = "rsa-private-key.pem"
// Name of the symmetric (AES) key to use
SymmetricKeyName = "symmetric-key-256"
)
func main() {
// Create a new Dapr SDK client
client, err := dapr.NewClient()
if err != nil {
log.Fatalf("Failed to initialize the Dapr client: %v", err)
}
defer client.Close()
// Step 1: encrypt a string using the RSA key, then decrypt it and show the output in the terminal
encryptDecryptString(client)
// Step 2: encrypt a large file and then decrypt it, using the AES key
encryptDecryptFile(client)
}
func encryptDecryptString(client dapr.Client) {
const message = `The secret is "passw0rd"`
// Encrypt the message
encStream, err := client.Encrypt(context.Background(),
strings.NewReader(message),
dapr.EncryptOptions{
ComponentName: CryptoComponentName,
// Name of the key to use
// Since this is a RSA key, we specify that as key wrapping algorithm
KeyName: RSAKeyName,
KeyWrapAlgorithm: "RSA",
},
)
if err != nil {
log.Fatalf("Failed to encrypt the message: %v", err)
}
// The method returns a readable stream, which we read in full in memory
encBytes, err := io.ReadAll(encStream)
if err != nil {
log.Fatalf("Failed to read the stream for the encrypted message: %v", err)
}
fmt.Printf("Encrypted the message, got %d bytes\n", len(encBytes))
// Now, decrypt the encrypted data
decStream, err := client.Decrypt(context.Background(),
bytes.NewReader(encBytes),
dapr.DecryptOptions{
// We just need to pass the name of the component
ComponentName: CryptoComponentName,
// Passing the name of the key is optional
KeyName: RSAKeyName,
},
)
if err != nil {
log.Fatalf("Failed to decrypt the message: %v", err)
}
// The method returns a readable stream, which we read in full in memory
decBytes, err := io.ReadAll(decStream)
if err != nil {
log.Fatalf("Failed to read the stream for the decrypted message: %v", err)
}
// Print the message on the console
fmt.Printf("Decrypted the message, got %d bytes\n", len(decBytes))
fmt.Println(string(decBytes))
}
func encryptDecryptFile(client dapr.Client) {
const fileName = "desert.jpg"
// Get a readable stream to the input file
plaintextF, err := os.Open(fileName)
if err != nil {
log.Fatalf("Failed to open plaintext file: %v", err)
}
defer plaintextF.Close()
// Encrypt the file
encStream, err := client.Encrypt(context.Background(),
plaintextF,
dapr.EncryptOptions{
ComponentName: CryptoComponentName,
// Name of the key to use
// Since this is a symmetric key, we specify AES as key wrapping algorithm
KeyName: SymmetricKeyName,
KeyWrapAlgorithm: "AES",
},
)
if err != nil {
log.Fatalf("Failed to encrypt the file: %v", err)
}
// Write the encrypted data to a file "encrypted.out"
encryptedF, err := os.Create("encrypted.out")
if err != nil {
log.Fatalf("Failed to open destination file: %v", err)
}
_, err = io.Copy(encryptedF, encStream)
if err != nil {
log.Fatalf("Failed to write encrypted stream to file: %v", err)
}
encryptedF.Close()
fmt.Println("Wrote encrypted data to encrypted.out")
// Now, decrypt the encrypted data
// First, open the file "encrypted.out" again, this time for reading
encryptedF, err = os.Open("encrypted.out")
if err != nil {
log.Fatalf("Failed to open encrypted file: %v", err)
}
defer encryptedF.Close()
// Now, decrypt the encrypted data
decStream, err := client.Decrypt(context.Background(),
encryptedF,
dapr.DecryptOptions{
// We just need to pass the name of the component
ComponentName: CryptoComponentName,
// Passing the name of the key is optional
KeyName: SymmetricKeyName,
},
)
if err != nil {
log.Fatalf("Failed to decrypt the file: %v", err)
}
// Write the decrypted data to a file "decrypted.out.jpg"
decryptedF, err := os.Create("decrypted.out.jpg")
if err != nil {
log.Fatalf("Failed to open destination file: %v", err)
}
_, err = io.Copy(decryptedF, decStream)
if err != nil {
log.Fatalf("Failed to write decrypted stream to file: %v", err)
}
decryptedF.Close()
fmt.Println("Wrote decrypted data to decrypted.out.jpg")
}

View File

@ -0,0 +1,43 @@
# Dapr Distributed Scheduler Example with go-sdk
## Steps
### Prepare
- Dapr installed (v1.14 or higher)
### Run Distributed Scheduling Example
<!-- STEP
name: Run Distributed Scheduling Example
output_match_mode: substring
expected_stdout_lines:
- 'Scheduler stream connected'
- 'schedulejob - success'
- 'job 0 received'
- 'payload: {db-backup {my-prod-db /backup-dir}}'
- 'job 1 received'
- 'payload: {db-backup {my-prod-db /backup-dir}}'
- 'job 2 received'
- 'payload: {db-backup {my-prod-db /backup-dir}}'
- 'getjob - resp: &{prod-db-backup @every 1s 10 value:"{\"task\":\"db-backup\",\"metadata\":{\"db_name\":\"my-prod-db\",\"backup_location\":\"/backup-dir\"}}"}'
- 'deletejob - success'
background: true
sleep: 30
-->
```bash
dapr run --app-id=distributed-scheduler \
--metrics-port=9091 \
--scheduler-host-address=localhost:50006 \
--dapr-grpc-port 50001 \
--app-port 50070 \
--app-protocol grpc \
--log-level debug \
go run ./main.go
```
<!-- END_STEP -->

View File

@ -0,0 +1,11 @@
package api
type Metadata struct {
DBName string `json:"db_name"`
BackupLocation string `json:"backup_location"`
}
type DBBackup struct {
Task string `json:"task"`
Metadata Metadata `json:"metadata"`
}

View File

@ -0,0 +1,105 @@
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"time"
"google.golang.org/protobuf/types/known/anypb"
daprc "github.com/dapr/go-sdk/client"
"github.com/dapr/go-sdk/examples/dist-scheduler/api"
"github.com/dapr/go-sdk/service/common"
daprs "github.com/dapr/go-sdk/service/grpc"
)
func main() {
server, err := daprs.NewService(":50070")
if err != nil {
log.Fatalf("failed to start the server: %v", err)
}
if err = server.AddJobEventHandler("prod-db-backup", prodDBBackupHandler); err != nil {
log.Fatalf("failed to register job event handler: %v", err)
}
log.Println("starting server")
go func() {
if err = server.Start(); err != nil {
log.Fatalf("failed to start server: %v", err)
}
}()
// Brief intermission to allow for the server to initialize.
time.Sleep(10 * time.Second)
ctx := context.Background()
jobData, err := json.Marshal(&api.DBBackup{
Task: "db-backup",
Metadata: api.Metadata{
DBName: "my-prod-db",
BackupLocation: "/backup-dir",
},
},
)
if err != nil {
panic(err)
}
job := daprc.Job{
Name: "prod-db-backup",
Schedule: "@every 1s",
Repeats: 10,
Data: &anypb.Any{
Value: jobData,
},
}
// create the client
client, err := daprc.NewClient()
if err != nil {
panic(err)
}
defer client.Close()
err = client.ScheduleJobAlpha1(ctx, &job)
if err != nil {
panic(err)
}
fmt.Println("schedulejob - success")
time.Sleep(3 * time.Second)
resp, err := client.GetJobAlpha1(ctx, "prod-db-backup")
if err != nil {
panic(err)
}
fmt.Printf("getjob - resp: %v\n", resp) // parse
err = client.DeleteJobAlpha1(ctx, "prod-db-backup")
if err != nil {
fmt.Printf("job deletion error: %v\n", err)
} else {
fmt.Println("deletejob - success")
}
if err = server.Stop(); err != nil {
log.Fatalf("failed to stop server: %v\n", err)
}
}
var jobCount = 0
func prodDBBackupHandler(ctx context.Context, job *common.JobEvent) error {
var jobPayload api.DBBackup
if err := json.Unmarshal(job.Data, &jobPayload); err != nil {
return fmt.Errorf("failed to unmarshal payload: %v", err)
}
fmt.Printf("job %d received:\n type: %v \n payload: %v\n", jobCount, job.JobType, jobPayload)
jobCount++
return nil
}

40
examples/go.mod Normal file
View File

@ -0,0 +1,40 @@
module github.com/dapr/go-sdk/examples
go 1.24.2
replace github.com/dapr/go-sdk => ../
require (
github.com/alecthomas/kingpin/v2 v2.4.0
github.com/dapr/go-sdk v0.0.0-00010101000000-000000000000
github.com/go-redis/redis/v8 v8.11.5
github.com/google/uuid v1.6.0
google.golang.org/grpc v1.72.0
google.golang.org/grpc/examples v0.0.0-20240516203910-e22436abb809
google.golang.org/protobuf v1.36.6
)
require (
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dapr/dapr v1.15.5 // indirect
github.com/dapr/durabletask-go v0.6.5 // indirect
github.com/dapr/kit v0.15.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/go-chi/chi/v5 v5.1.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e // indirect
)

105
examples/go.sum Normal file
View File

@ -0,0 +1,105 @@
github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/dapr/dapr v1.15.5 h1:bkCmcQQfaQ5C49P3l0elCzDr4/Oja5kitM3jStY+2RY=
github.com/dapr/dapr v1.15.5/go.mod h1:wwopO8AD9CZOgVj4bsdXNmeQujMo0v3MLAqeaX+gb00=
github.com/dapr/durabletask-go v0.6.5 h1:aWcxMfYudojpgRjJRdUr7yyZ7rGcvLtWXUuA4cGHBR0=
github.com/dapr/durabletask-go v0.6.5/go.mod h1:nTZ5fCbJLnZbVdi6Z2YxdDF1OgQZL3LroogGuetrwuA=
github.com/dapr/kit v0.15.2 h1:5H9IhKScU/SpE2Hxvr5vUlmYN1e2MJN15RoT8/KSziU=
github.com/dapr/kit v0.15.2/go.mod h1:HwFsBKEbcyLanWlDZE7u/jnaDCD/tU+n3pkFNUctQNw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2 h1:IqsN8hx+lWLqlN+Sc3DoMy/watjofWiU8sRFgQ8fhKM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
google.golang.org/grpc/examples v0.0.0-20240516203910-e22436abb809 h1:f96Rv5C5Y2CWlbKK6KhKDdyFgGOjPHPEMsdyaxE9k0c=
google.golang.org/grpc/examples v0.0.0-20240516203910-e22436abb809/go.mod h1:uaPEAc5V00jjG3DPhGFLXGT290RUV3+aNQigs1W50/8=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=

View File

@ -17,7 +17,8 @@ output_match_mode: substring
expected_stdout_lines:
- 'Received: Dapr'
background: true
sleep: 15
sleep: 30
timeout_seconds: 60
-->
```bash
@ -39,6 +40,7 @@ expected_stdout_lines:
output_match_mode: substring
background: true
sleep: 15
timeout_seconds: 60
-->
```bash
@ -50,15 +52,6 @@ dapr run --app-id grpc-client \
### Cleanup
<!-- STEP
expected_stdout_lines:
- '✅ app stopped successfully: grpc-server'
expected_stderr_lines:
name: Shutdown dapr
-->
```bash
dapr stop --app-id grpc-server
```
<!-- END_STEP -->

View File

@ -1,20 +0,0 @@
module github.com/dapr/go-sdk/examples/grpc-service
go 1.19
replace github.com/dapr/go-sdk => ../../
require (
github.com/dapr/go-sdk v0.0.0-00010101000000-000000000000
google.golang.org/grpc v1.55.0
google.golang.org/grpc/examples v0.0.0-20230602173802-c9d3ea567325
)
require (
github.com/golang/protobuf v1.5.3 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
google.golang.org/protobuf v1.30.0 // indirect
)

View File

@ -1,26 +0,0 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
google.golang.org/grpc/examples v0.0.0-20230602173802-c9d3ea567325 h1:2RthLftQfQtpQMEmkGxDGs+PAG/sVWONfKd7km4DRzM=
google.golang.org/grpc/examples v0.0.0-20230602173802-c9d3ea567325/go.mod h1:JFf2mvgu0u96q6WJc59JQq9E9SQ6E93ML1ozmUNjW8k=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@ -23,7 +23,8 @@ This quickstart requires you to have the following installed on your machine:
## Step 1 - Setup Dapr
Follow [instructions](https://docs.dapr.io/getting-started/install-dapr/) to download and install the Dapr CLI and initialize Dapr.
- [Install the Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialise Dapr Locally](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
## Step 2 - Understand the code
@ -81,6 +82,7 @@ There are two ways to launch Dapr applications. You can pass the app executable
name: Run and send order
background: true
sleep: 5
timeout_seconds: 60
expected_stdout_lines:
- '== APP == dapr client initializing for: 127.0.0.1:3500'
- '== APP == Sending order ID 20'
@ -97,6 +99,7 @@ dapr run --app-id order-app --dapr-grpc-port 3500 --log-level error -- ./order p
name: Run and get order
background: true
sleep: 5
timeout_seconds: 60
expected_stdout_lines:
- '== APP == dapr client initializing for: 127.0.0.1:3500'
- '== APP == Getting order'

View File

@ -1,26 +0,0 @@
module github.com/dapr/go-sdk/examples/hello-world
go 1.19
// Needed to validate SDK changes in CI/CD
replace github.com/dapr/go-sdk => ../../
require (
github.com/dapr/go-sdk v0.0.0-00010101000000-000000000000
gopkg.in/alecthomas/kingpin.v2 v2.2.6
)
require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf // indirect
google.golang.org/grpc v1.51.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,48 +0,0 @@
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf h1:/JqRexUvugu6JURQ0O7RfV1EnvgrOxUV4tSjuAv0Sr0=
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -20,7 +20,7 @@ import (
"strconv"
"time"
"gopkg.in/alecthomas/kingpin.v2"
"github.com/alecthomas/kingpin/v2"
dapr "github.com/dapr/go-sdk/client"
)

View File

@ -21,6 +21,7 @@ expected_stdout_lines:
- 'event - PubsubName: messages, Topic: neworder'
background: true
sleep: 15
timeout_seconds: 60
-->
```bash
@ -43,6 +44,7 @@ expected_stdout_lines:
- '== APP == data published'
background: true
sleep: 15
timeout_seconds: 60
-->
```bash
@ -58,20 +60,11 @@ dapr run --app-id pub \
### Cleanup
<!-- STEP
expected_stdout_lines:
- '✅ app stopped successfully: sub'
expected_stderr_lines:
name: Shutdown dapr
-->
```bash
dapr stop --app-id sub
(lsof -i:8080 | grep sub) | awk '{print $2}' | xargs kill
```
<!-- END_STEP -->
## Result
```shell

View File

@ -1,22 +0,0 @@
module github.com/dapr/go-sdk/examples/pubsub
go 1.19
// Needed to validate SDK changes in CI/CD
replace github.com/dapr/go-sdk => ../../
require github.com/dapr/go-sdk v0.0.0-00010101000000-000000000000
require (
github.com/go-chi/chi/v5 v5.0.8 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf // indirect
google.golang.org/grpc v1.51.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,40 +0,0 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf h1:/JqRexUvugu6JURQ0O7RfV1EnvgrOxUV4tSjuAv0Sr0=
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -16,7 +16,8 @@ output_match_mode: substring
expected_stdout_lines:
- "ContentType:text/plain, Verb:POST, QueryString:, hellow"
background: true
sleep: 15
sleep: 30
timeout_seconds: 60
-->
```bash
@ -60,6 +61,7 @@ expected_stdout_lines:
- '== APP == output binding invoked'
background: true
sleep: 15
timeout_seconds: 60
-->
```bash
@ -89,7 +91,7 @@ expected_stdout_lines:
```bash
dapr run --app-id custom-grpc-client \
-d ./config \
--dapr-http-max-request-size 41 \
--max-body-size 41Mi \
--log-level debug \
go run ./custom-grpc-client/main.go
```
@ -155,17 +157,7 @@ Uses the [config/cron.yaml](config/cron.yaml) component
### Cleanup
<!-- STEP
expected_stdout_lines:
- '✅ app stopped successfully: serving'
expected_stderr_lines:
name: Shutdown dapr
-->
```bash
dapr stop --app-id serving
(lsof -i:8080 | grep main) | awk '{print $2}' | xargs kill
```
<!-- END_STEP -->

View File

@ -95,7 +95,7 @@ func main() {
in := &dapr.InvokeBindingRequest{
Name: "example-http-binding",
Operation: "create",
Operation: "get",
}
if err := client.InvokeOutputBinding(ctx, in); err != nil {
panic(err)

View File

@ -7,6 +7,6 @@ spec:
version: v1
metadata:
- name: url
value: https://http2.pro/api/v1
value: https://sandbox.api.service.nhs.uk/hello-world/hello/world
- name: method
value: GET

View File

@ -1,24 +0,0 @@
module github.com/dapr/go-sdk/examples/service
go 1.19
// Needed to validate SDK changes in CI/CD
replace github.com/dapr/go-sdk => ../../
require (
github.com/dapr/go-sdk v0.0.0-00010101000000-000000000000
google.golang.org/grpc v1.52.3
)
require (
github.com/go-chi/chi/v5 v5.0.8 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
golang.org/x/net v0.5.0 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/text v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,40 +0,0 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf h1:/JqRexUvugu6JURQ0O7RfV1EnvgrOxUV4tSjuAv0Sr0=
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/grpc v1.52.3 h1:pf7sOysg4LdgBqduXveGKrcEwbStiK2rtfghdzlUYDQ=
google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -12,7 +12,8 @@ This quickstart requires you to have the following installed on your machine:
## Step 1 - Setup Dapr
Follow [instructions](https://docs.dapr.io/getting-started/install-dapr/) to download and install the Dapr CLI and initialize Dapr.
- [Install the Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialise Dapr Locally](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
## Step 2 - Understand the code
@ -69,6 +70,7 @@ There are two ways to launch Dapr applications. You can pass the app executable
name: Run and send order
background: true
sleep: 5
timeout_seconds: 60
expected_stdout_lines:
- '== APP == dapr client initializing for: /tmp/dapr-order-app-grpc.socket'
- '== APP == Sending order ID 20'
@ -85,6 +87,7 @@ dapr run --app-id order-app --log-level error --unix-domain-socket /tmp -- ./ord
name: Run and get order
background: true
sleep: 5
timeout_seconds: 60
expected_stdout_lines:
- '== APP == dapr client initializing for: /tmp/dapr-order-app-grpc.socket'
- '== APP == Getting order'

View File

@ -1,26 +0,0 @@
module github.com/dapr/go-sdk/examples/socket
go 1.19
// Needed to validate SDK changes in CI/CD
replace github.com/dapr/go-sdk => ../../
require (
github.com/dapr/go-sdk v0.0.0-00010101000000-000000000000
gopkg.in/alecthomas/kingpin.v2 v2.2.6
)
require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
golang.org/x/net v0.5.0 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/text v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf // indirect
google.golang.org/grpc v1.51.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,48 +0,0 @@
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf h1:/JqRexUvugu6JURQ0O7RfV1EnvgrOxUV4tSjuAv0Sr0=
google.golang.org/genproto v0.0.0-20230104163317-caabf589fcbf/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -6,8 +6,8 @@ import (
"strconv"
"time"
"github.com/alecthomas/kingpin/v2"
dapr "github.com/dapr/go-sdk/client"
"gopkg.in/alecthomas/kingpin.v2"
)
const (

Some files were not shown because too many files have changed in this diff Show More