Skip to content

Commit

Permalink
Merge pull request #6 from restatedev/first-e2e-tests
Browse files Browse the repository at this point in the history
Setup CI, prepare test-services
  • Loading branch information
slinkydeveloper authored Aug 19, 2024
2 parents 1aeab48 + fdb0955 commit 0be7406
Show file tree
Hide file tree
Showing 10 changed files with 395 additions and 15 deletions.
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.github
.idea
target
tests
43 changes: 43 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: CI

on:
pull_request:
workflow_call:
workflow_dispatch:
push:
branches:
- main

jobs:
build-and-test:
name: Build and test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: read
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04]
env:
RUST_BACKTRACE: full
steps:
- uses: actions/checkout@v4

- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: clippy
rustflags: ""

- name: Install nextest
uses: taiki-e/install-action@nextest

- name: Setup just
uses: extractions/setup-just@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Run verify
run: just verify
123 changes: 123 additions & 0 deletions .github/workflows/integration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
name: Integration

# Controls when the workflow will run
on:
pull_request:
push:
branches:
- main
schedule:
- cron: '0 */6 * * *' # Every 6 hours
workflow_dispatch:
inputs:
restateCommit:
description: 'restate commit'
required: false
default: ''
type: string
restateImage:
description: 'restate image, superseded by restate commit'
required: false
default: 'ghcr.io/restatedev/restate:main'
type: string
workflow_call:
inputs:
restateCommit:
description: 'restate commit'
required: false
default: ''
type: string
restateImage:
description: 'restate image, superseded by restate commit'
required: false
default: 'ghcr.io/restatedev/restate:main'
type: string

jobs:

sdk-test-suite:
if: github.repository_owner == 'restatedev'
runs-on: ubuntu-latest
name: "Features integration test (sdk-test-suite version ${{ matrix.sdk-test-suite }})"
strategy:
matrix:
sdk-test-suite: [ "1.8" ]
permissions:
contents: read
issues: read
checks: write
pull-requests: write
actions: read

steps:
- uses: actions/checkout@v4
with:
repository: restatedev/sdk-rust

### Download the Restate container image, if needed
# Setup restate snapshot if necessary
# Due to https://github.com/actions/upload-artifact/issues/53
# We must use download-artifact to get artifacts created during *this* workflow run, ie by workflow call
- name: Download restate snapshot from in-progress workflow
if: ${{ inputs.restateCommit != '' && github.event_name != 'workflow_dispatch' }}
uses: actions/download-artifact@v4
with:
name: restate.tar
# In the workflow dispatch case where the artifact was created in a previous run, we can download as normal
- name: Download restate snapshot from completed workflow
if: ${{ inputs.restateCommit != '' && github.event_name == 'workflow_dispatch' }}
uses: dawidd6/action-download-artifact@v3
with:
repo: restatedev/restate
workflow: ci.yml
commit: ${{ inputs.restateCommit }}
name: restate.tar
- name: Install restate snapshot
if: ${{ inputs.restateCommit != '' }}
run: |
output=$(docker load --input restate.tar)
docker tag "${output#*: }" "localhost/restatedev/restate-commit-download:latest"
docker image ls -a
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Setup sdk-test-suite
run: wget --no-verbose https://github.com/restatedev/sdk-test-suite/releases/download/v${{ matrix.sdk-test-suite }}/restate-sdk-test-suite.jar

- name: Build Rust test-services image
id: build
uses: docker/build-push-action@v6
with:
context: .
file: "test-services/Dockerfile"
push: false
load: true
tags: localhost/restatedev/test-services:latest
cache-from: type=gha,scope=${{ github.workflow }}
cache-to: type=gha,mode=max,scope=${{ github.workflow }}

# Run test suite
- name: Run test suite
env:
RESTATE_CONTAINER_IMAGE: ${{ inputs.restateCommit != '' && 'localhost/restatedev/restate-commit-download:latest' || (inputs.restateImage != '' && inputs.restateImage || 'ghcr.io/restatedev/restate:main') }}
run: java -jar restate-sdk-test-suite.jar run --report-dir=test-report --exclusions-file test-services/exclusions.yaml localhost/restatedev/test-services:latest

# Upload logs and publish test result
- uses: actions/upload-artifact@v4
if: always() # Make sure this is run even when test fails
with:
name: sdk-rust-integration-test-report
path: test-report
- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
files: |
test-report/*/*.xml
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ hyper-util = { version = "0.1", features = ["tokio", "server", "server-graceful"
pin-project-lite = "0.2"
regress = "0.10"
restate-sdk-derive = { version = "0.0.1", path = "derive" }
restate-sdk-shared-core = { path = "../sdk-shared-core" }
restate-sdk-shared-core = { version = "0.0.5" }
serde = "1.0"
serde_json = "1.0"
thiserror = "1.0.63"
Expand All @@ -39,4 +39,4 @@ syn = "2.0"
typify = { version = "0.1.0" }

[workspace]
members = ["derive"]
members = ["derive", "test-services"]
76 changes: 63 additions & 13 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,93 @@ use std::fmt;
use std::future::Future;
use std::time::Duration;

pub struct Context<'a>(&'a ContextInternal);
pub struct Context<'a> {
inner: &'a ContextInternal,
}

impl<'a> From<(&'a ContextInternal, InputMetadata)> for Context<'a> {
fn from(value: (&'a ContextInternal, InputMetadata)) -> Self {
Self(value.0)
Self { inner: value.0 }
}
}

pub struct SharedObjectContext<'a>(pub(crate) &'a ContextInternal);
pub struct SharedObjectContext<'a> {
key: String,
pub(crate) inner: &'a ContextInternal,
}

impl<'a> SharedObjectContext<'a> {
pub fn key(&self) -> &str {
&self.key
}
}

impl<'a> From<(&'a ContextInternal, InputMetadata)> for SharedObjectContext<'a> {
fn from(value: (&'a ContextInternal, InputMetadata)) -> Self {
Self(value.0)
Self {
key: value.1.key,
inner: value.0,
}
}
}

pub struct ObjectContext<'a>(pub(crate) &'a ContextInternal);
pub struct ObjectContext<'a> {
key: String,
pub(crate) inner: &'a ContextInternal,
}

impl<'a> ObjectContext<'a> {
pub fn key(&self) -> &str {
&self.key
}
}

impl<'a> From<(&'a ContextInternal, InputMetadata)> for ObjectContext<'a> {
fn from(value: (&'a ContextInternal, InputMetadata)) -> Self {
Self(value.0)
Self {
key: value.1.key,
inner: value.0,
}
}
}

pub struct SharedWorkflowContext<'a>(pub(crate) &'a ContextInternal);
pub struct SharedWorkflowContext<'a> {
key: String,
pub(crate) inner: &'a ContextInternal,
}

impl<'a> From<(&'a ContextInternal, InputMetadata)> for SharedWorkflowContext<'a> {
fn from(value: (&'a ContextInternal, InputMetadata)) -> Self {
Self(value.0)
Self {
key: value.1.key,
inner: value.0,
}
}
}

impl<'a> SharedWorkflowContext<'a> {
pub fn key(&self) -> &str {
&self.key
}
}

pub struct WorkflowContext<'a>(pub(crate) &'a ContextInternal);
pub struct WorkflowContext<'a> {
key: String,
pub(crate) inner: &'a ContextInternal,
}

impl<'a> From<(&'a ContextInternal, InputMetadata)> for WorkflowContext<'a> {
fn from(value: (&'a ContextInternal, InputMetadata)) -> Self {
Self(value.0)
Self {
key: value.1.key,
inner: value.0,
}
}
}

impl<'a> WorkflowContext<'a> {
pub fn key(&self) -> &str {
&self.key
}
}

Expand All @@ -58,15 +108,15 @@ macro_rules! impl_context_method {
impl<'a> $ctx<'a> {
#[doc = $doc]
pub fn $name $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? (&self, $($param: $ty),*) -> impl Future<Output=$ret> + 'a {
self.0.$name($($param),*)
self.inner.$name($($param),*)
}
}
};
(@render_impl $ctx:ident; #[doc = $doc:expr] fn $name:ident $(< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)? ($($param:ident : $ty:ty),*) -> $ret:ty $(where $( $wlt:tt $( : $wclt:tt $(+ $wdlt:tt )* )? ),+ )?) => {
impl<'a> $ctx<'a> {
#[doc = $doc]
pub fn $name $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? (&self, $($param: $ty),*) -> $ret {
self.0.$name($($param),*)
self.inner.$name($($param),*)
}
}
};
Expand Down Expand Up @@ -264,7 +314,7 @@ macro_rules! impl_run_method {
T: Serialize + Deserialize,
F: Future<Output = HandlerResult<T>> + Send + Sync + 'a,
{
self.0.run(name, run_closure)
self.inner.run(name, run_closure)
}
}
};
Expand Down
12 changes: 12 additions & 0 deletions test-services/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "test-services"
version = "0.1.0"
edition = "2021"
publish = false

[dependencies]
tokio = { version = "1", features = ["full"] }
tracing-subscriber = "0.3"
restate-sdk = { path = ".." }
serde = { version = "1", features = ["derive"] }
tracing = "0.1.40"
11 changes: 11 additions & 0 deletions test-services/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM rust:1.78

WORKDIR /app

COPY . .
RUN cargo build -p test-services
RUN cp ./target/debug/test-services /bin/server

ENV RUST_LOG="debug,restate_shared_core=trace"

CMD ["/bin/server"]
49 changes: 49 additions & 0 deletions test-services/exclusions.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
exclusions:
"alwaysSuspending":
- "dev.restate.sdktesting.tests.AwaitTimeout"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication"
- "dev.restate.sdktesting.tests.SideEffect"
- "dev.restate.sdktesting.tests.Sleep"
- "dev.restate.sdktesting.tests.SleepWithFailures"
- "dev.restate.sdktesting.tests.State"
- "dev.restate.sdktesting.tests.UpgradeWithInFlightInvocation"
- "dev.restate.sdktesting.tests.UpgradeWithNewInvocation"
- "dev.restate.sdktesting.tests.UserErrors"
- "dev.restate.sdktesting.tests.WorkflowAPI"
"default":
- "dev.restate.sdktesting.tests.AwaitTimeout"
- "dev.restate.sdktesting.tests.CallOrdering"
- "dev.restate.sdktesting.tests.CancelInvocation"
- "dev.restate.sdktesting.tests.Ingress"
- "dev.restate.sdktesting.tests.KafkaIngress"
- "dev.restate.sdktesting.tests.KillInvocation"
- "dev.restate.sdktesting.tests.PrivateService"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication"
- "dev.restate.sdktesting.tests.Sleep"
- "dev.restate.sdktesting.tests.SleepWithFailures"
- "dev.restate.sdktesting.tests.State"
- "dev.restate.sdktesting.tests.UpgradeWithInFlightInvocation"
- "dev.restate.sdktesting.tests.UpgradeWithNewInvocation"
- "dev.restate.sdktesting.tests.UserErrors"
- "dev.restate.sdktesting.tests.WorkflowAPI"
"lazyState":
- "dev.restate.sdktesting.tests.State"
"persistedTimers":
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication"
- "dev.restate.sdktesting.tests.Sleep"
"singleThreadSinglePartition":
- "dev.restate.sdktesting.tests.AwaitTimeout"
- "dev.restate.sdktesting.tests.CallOrdering"
- "dev.restate.sdktesting.tests.CancelInvocation"
- "dev.restate.sdktesting.tests.Ingress"
- "dev.restate.sdktesting.tests.KafkaIngress"
- "dev.restate.sdktesting.tests.KillInvocation"
- "dev.restate.sdktesting.tests.PrivateService"
- "dev.restate.sdktesting.tests.ServiceToServiceCommunication"
- "dev.restate.sdktesting.tests.Sleep"
- "dev.restate.sdktesting.tests.SleepWithFailures"
- "dev.restate.sdktesting.tests.State"
- "dev.restate.sdktesting.tests.UpgradeWithInFlightInvocation"
- "dev.restate.sdktesting.tests.UpgradeWithNewInvocation"
- "dev.restate.sdktesting.tests.UserErrors"
- "dev.restate.sdktesting.tests.WorkflowAPI"
Loading

0 comments on commit 0be7406

Please sign in to comment.