Skip to content

Commit

Permalink
WIP: Docker integration tests
Browse files Browse the repository at this point in the history
Docker based integration tests for networked calls (eventually) using the containers as mock hosts.

Additionally adds some missing predefined serialization implementations for `Vec<T>` concrete types and `char`
  • Loading branch information
slawlor committed Jan 31, 2023
1 parent 3031d3d commit d6016e7
Show file tree
Hide file tree
Showing 30 changed files with 1,122 additions and 316 deletions.
20 changes: 20 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Cargo
# will have compiled files and executables
/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# Remove all target compilation folders from all sub-folders as well
**/target/

# Remove code-coverage generated files from git
debug/
coverage/
**/*.profraw

.github/
40 changes: 40 additions & 0 deletions .github/workflows/integration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Ractor Cluster integration tests
on:
push:
branches:
- main
paths:
- 'ractor_cluster*/**'
pull_request:
types: [opened, reopened, synchronize]
paths:
- 'ractor_cluster*/**'

jobs:
test:
name: Test ractor_cluster with Docker based networked images
runs-on: ${{matrix.os}}-latest
strategy:
fail-fast: false
matrix:
toolchain: [stable]
os: [ubuntu]

steps:
- uses: actions/checkout@main

- name: Build the docker image
working-directory: .
run: |
docker compose build
- name: Authentication Handshake
working-directory: .
run: |
docker compose --env-file ./ractor_cluster_integration_tests/envs/auth-handshake.env up --exit-code-from node-b
- name: Process Groups
working-directory: .
run: |
docker compose --env-file ./ractor_cluster_integration_tests/envs/pg-groups.env up --exit-code-from node-b
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ members = [
"ractor_cluster",
"ractor_cluster_derive",
"ractor_playground",
"ractor_cluster_integration_tests",
"xtask"
]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A pure-Rust actor framework. Inspired from [Erlang's `gen_server`](https://www.e
[<img alt="github" src="https://img.shields.io/badge/github-slawlor/ractor-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/slawlor/ractor)
[<img alt="crates.io" src="https://img.shields.io/crates/v/ractor.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/ractor)
[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-ractor-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/ractor)
[![CI/main](https://github.com/slawlor/repl/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/slawlor/repl/actions/workflows/ci.yaml)
[![CI/main](https://github.com/slawlor/ractor/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/slawlor/ractor/actions/workflows/ci.yaml)
[![codecov](https://codecov.io/gh/slawlor/ractor/branch/main/graph/badge.svg?token=61AGYYPWBA)](https://codecov.io/gh/slawlor/ractor)
![Downloads](https://img.shields.io/crates/d/ractor.svg)

Expand Down
2 changes: 1 addition & 1 deletion codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ ignore:
- "xtask"
- "ractor/examples"
- "ractor/benches"
- "ractor_cluster" # for now
- "ractor_cluster_derive"
- "ractor_cluster_integration_tests"
31 changes: 31 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
version: '3.3'
services:
node-a:
container_name: "node-a"
build:
context: .
dockerfile: ractor_cluster_integration_tests/Dockerfile
image: ractor_cluster_tests:latest
networks:
- test-net
entrypoint: ''
command: ractor_cluster_integration_tests test ${A_TEST}
environment:
RUST_LOG: debug
node-b:
depends_on:
- node-a
container_name: "node-b"
build:
context: .
dockerfile: ractor_cluster_integration_tests/Dockerfile
image: ractor_cluster_tests:latest
networks:
- test-net
entrypoint: ''
command: ractor_cluster_integration_tests test ${B_TEST}
environment:
RUST_LOG: debug
networks:
test-net:
external: false
2 changes: 1 addition & 1 deletion ractor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ractor"
version = "0.6.0"
version = "0.6.1"
authors = ["Sean Lawlor", "Evan Au", "Dillon George"]
description = "A actor framework for Rust"
documentation = "https://docs.rs/ractor"
Expand Down
6 changes: 4 additions & 2 deletions ractor/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ pub trait Message: Any + Send + Sized + 'static {

/// Convert this message to a [BoxedMessage]
#[cfg(not(feature = "cluster"))]
fn box_message(self, _pid: &ActorId) -> Result<BoxedMessage, BoxedDowncastErr> {
#[allow(unused_variables)]
fn box_message(self, pid: &ActorId) -> Result<BoxedMessage, BoxedDowncastErr> {
Ok(BoxedMessage {
msg: Some(Box::new(self)),
})
Expand All @@ -154,7 +155,8 @@ pub trait Message: Any + Send + Sized + 'static {

/// Deserialize binary data to this message type
#[cfg(feature = "cluster")]
fn deserialize(_bytes: SerializedMessage) -> Result<Self, BoxedDowncastErr> {
#[allow(unused_variables)]
fn deserialize(bytes: SerializedMessage) -> Result<Self, BoxedDowncastErr> {
Err(BoxedDowncastErr)
}
}
Expand Down
1 change: 1 addition & 0 deletions ractor/src/port/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub use output::*;

/// A remote procedure call's reply port. Wrapper of [concurrency::OneshotSender] with a
/// consistent error type
#[derive(Debug)]
pub struct RpcReplyPort<TMsg> {
port: concurrency::OneshotSender<TMsg>,
timeout: Option<concurrency::Duration>,
Expand Down
3 changes: 2 additions & 1 deletion ractor_cluster/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ractor_cluster"
version = "0.6.0"
version = "0.6.1"
authors = ["Sean Lawlor", "Evan Au", "Dillon George"]
description = "Distributed cluster environment of Ractor actors"
documentation = "https://docs.rs/ractor"
Expand Down Expand Up @@ -34,4 +34,5 @@ tokio = { version = "1", features = ["rt", "time", "sync", "macros", "net", "io-
# tokio-rustls = { version = "0.23", optional = true }

[dev-dependencies]
paste = "1"
tokio = { version = "1", features = ["rt", "time", "sync", "macros", "net", "io-util", "rt-multi-thread"] }
2 changes: 1 addition & 1 deletion ractor_cluster/src/node/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl From<MessagingErr> for ClientConnectErr {
/// Returns: [Ok(())] if the connection was successful and the [super::NodeSession] was started. Handshake will continue
/// automatically. Results in a [Err(ClientConnectError)] if any part of the process failed to initiate
pub async fn connect<T>(
node_server: ActorRef<super::NodeServer>,
node_server: &ActorRef<super::NodeServer>,
address: T,
) -> Result<(), ClientConnectErr>
where
Expand Down
23 changes: 19 additions & 4 deletions ractor_cluster/src/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ use std::{cmp::Ordering, collections::hash_map::Entry};
use ractor::{cast, Actor, ActorId, ActorProcessingErr, ActorRef, RpcReplyPort, SupervisionEvent};

use crate::protocol::auth as auth_protocol;
use crate::RactorMessage;
use crate::{NodeId, RactorMessage};

const PROTOCOL_VERSION: u32 = 1;

Expand Down Expand Up @@ -120,6 +120,9 @@ pub enum NodeServerMessage {
/// The node's name (now that we've received it)
name: auth_protocol::NameMessage,
},

/// Retrieve the current status of the node server, listing the node sessions
GetSessions(RpcReplyPort<HashMap<NodeId, ActorRef<NodeSession>>>),
}

/// Message from the TCP `ractor_cluster::net::session::Session` actor and the
Expand All @@ -134,6 +137,9 @@ pub enum NodeSessionMessage {

/// Send a message over the node channel to the remote `node()`
SendMessage(crate::protocol::node::NodeMessage),

/// Retrieve whether the session is authenticated or not
GetAuthenticationState(RpcReplyPort<bool>),
}

/// Represents the server which is managing all node session instances
Expand Down Expand Up @@ -170,14 +176,16 @@ struct NodeServerSessionInformation {
actor: ActorRef<NodeSession>,
peer_name: Option<auth_protocol::NameMessage>,
is_server: bool,
node_id: NodeId,
}

impl NodeServerSessionInformation {
fn new(actor: ActorRef<NodeSession>, is_server: bool) -> Self {
fn new(actor: ActorRef<NodeSession>, is_server: bool, node_id: NodeId) -> Self {
Self {
actor,
peer_name: None,
is_server,
node_id,
}
}

Expand All @@ -190,7 +198,7 @@ impl NodeServerSessionInformation {
pub struct NodeServerState {
listener: ActorRef<crate::net::listener::Listener>,
node_sessions: HashMap<ActorId, NodeServerSessionInformation>,
node_id_counter: u64,
node_id_counter: NodeId,
this_node_name: auth_protocol::NameMessage,
}

Expand Down Expand Up @@ -274,7 +282,7 @@ impl Actor for NodeServer {
let _ = cast!(actor, NodeSessionMessage::SetTcpStream(stream));
state.node_sessions.insert(
actor.get_id(),
NodeServerSessionInformation::new(actor.clone(), is_server),
NodeServerSessionInformation::new(actor.clone(), is_server, node_id),
);
state.node_id_counter += 1;
} else {
Expand All @@ -291,6 +299,13 @@ impl Actor for NodeServer {
Self::Msg::CheckSession { peer_name, reply } => {
let _ = reply.send(state.check_peers(peer_name));
}
Self::Msg::GetSessions(reply) => {
let mut map = HashMap::new();
for value in state.node_sessions.values() {
map.insert(value.node_id, value.actor.clone());
}
let _ = reply.send(map);
}
}
Ok(())
}
Expand Down
3 changes: 3 additions & 0 deletions ractor_cluster/src/node/node_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,9 @@ impl Actor for NodeSession {
Self::Msg::SendMessage(node_message) if state.tcp.is_some() => {
state.tcp_send_node(node_message);
}
Self::Msg::GetAuthenticationState(reply) => {
let _ = reply.send(state.auth.is_ok());
}
_ => {
// no-op, ignore
}
Expand Down
Loading

0 comments on commit d6016e7

Please sign in to comment.