Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions linera-sdk/tests/fixtures/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions linera-sdk/tests/fixtures/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ resolver = "2"
members = [
"contract-call",
"create-and-call",
"graph-ql-queries",
"meta-counter",
"publish-read-data-blob",
"time-expiry",
Expand All @@ -20,6 +21,7 @@ contract-call = { path = "./create-and-call" }
counter = { path = "../../../examples/counter" }
counter-no-graphql = { path = "../../../examples/counter-no-graphql" }
create-and-call = { path = "./create-and-call" }
graph-ql-queries = { path = "./graph-ql-queries" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: let's be consistent with the spelling graphql.

meta-counter = { path = "./meta-counter" }
publish-read-data-blob = { path = "./publish-read-data-blob" }
time-expiry = { path = "./time-expiry" }
Expand Down
25 changes: 25 additions & 0 deletions linera-sdk/tests/fixtures/graph-ql-queries/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "graph-ql-queries"
version = "0.1.0"
authors = ["Linera <[email protected]>"]
edition = "2021"

[dependencies]
async-graphql.workspace = true
linera-sdk.workspace = true
serde.workspace = true

[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
linera-sdk = { workspace = true, features = ["test", "wasmer"] }
tokio = { workspace = true, features = ["rt", "sync"] }

[dev-dependencies]
linera-sdk = { workspace = true, features = ["test"] }

[[bin]]
name = "graph_ql_queries_contract"
path = "src/contract.rs"

[[bin]]
name = "graph_ql_queries_service"
path = "src/service.rs"
68 changes: 68 additions & 0 deletions linera-sdk/tests/fixtures/graph-ql-queries/src/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) Zefchain Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

#![cfg_attr(target_arch = "wasm32", no_main)]

mod state;

use graph_ql_queries::{GraphQlQueriesAbi, GraphQlQueriesOperation, GraphQlQueriesOperation::*};
use linera_sdk::{
linera_base_types::WithContractAbi,
views::{RootView, View},
Contract, ContractRuntime,
};

use self::state::GraphQlQueriesState;

pub struct GraphQlQueriesContract {
state: GraphQlQueriesState,
}

linera_sdk::contract!(GraphQlQueriesContract);

impl WithContractAbi for GraphQlQueriesContract {
type Abi = GraphQlQueriesAbi;
}

impl Contract for GraphQlQueriesContract {
type Message = ();
type InstantiationArgument = ();
type Parameters = ();
type EventValue = ();

async fn load(runtime: ContractRuntime<Self>) -> Self {
let state = GraphQlQueriesState::load(runtime.root_view_storage_context())
.await
.expect("Failed to load state");
GraphQlQueriesContract { state }
}

async fn instantiate(&mut self, _value: ()) {}

async fn execute_operation(&mut self, operation: GraphQlQueriesOperation) {
match operation {
SetRegister { value } => {
self.state.reg.set(value);
}
InsertMapString { key, value } => {
self.state.map_s.insert(&key, value).unwrap();
}
InsertCollString { key, value } => {
let subview = self.state.coll_s.load_entry_mut(&key).await.unwrap();
subview.set(value);
}
InsertCollMap { key1, key2, value } => {
let subview = self.state.coll_map.load_entry_mut(&key1).await.unwrap();
subview.insert(&key2, value).unwrap();
}
}
}

async fn execute_message(&mut self, _message: ()) {
panic!("Counter application doesn't support any cross-chain messages");
}

async fn store(mut self) {
self.state.save().await.expect("Failed to save state");
}
}
39 changes: 39 additions & 0 deletions linera-sdk/tests/fixtures/graph-ql-queries/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) Zefchain Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/*! ABI of the Counter Example Application */

use async_graphql::{Request, Response};
use linera_sdk::{
graphql::GraphQLMutationRoot,
linera_base_types::{ContractAbi, ServiceAbi},
};
use serde::{Deserialize, Serialize};

pub struct GraphQlQueriesAbi;

#[derive(Debug, Deserialize, Serialize, GraphQLMutationRoot)]
pub enum GraphQlQueriesOperation {
/// Set the register
SetRegister { value: u64 },
/// Insert in MapView
InsertMapString { key: String, value: u8 },
/// Insert in CollectionView
InsertCollString { key: String, value: u8 },
/// Insertion in the CollectionView / MapView
InsertCollMap {
key1: String,
key2: String,
value: u64,
},
}

impl ContractAbi for GraphQlQueriesAbi {
type Operation = GraphQlQueriesOperation;
type Response = ();
}

impl ServiceAbi for GraphQlQueriesAbi {
type Query = Request;
type QueryResponse = Response;
}
52 changes: 52 additions & 0 deletions linera-sdk/tests/fixtures/graph-ql-queries/src/service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) Zefchain Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

#![cfg_attr(target_arch = "wasm32", no_main)]

mod state;

use std::sync::Arc;

use async_graphql::{EmptySubscription, Request, Response, Schema};
use graph_ql_queries::{GraphQlQueriesAbi, GraphQlQueriesOperation};
use linera_sdk::{
graphql::GraphQLMutationRoot as _, linera_base_types::WithServiceAbi, views::View, Service,
ServiceRuntime,
};

use self::state::GraphQlQueriesState;

pub struct GraphQlQueriesService {
state: Arc<GraphQlQueriesState>,
runtime: Arc<ServiceRuntime<Self>>,
}

linera_sdk::service!(GraphQlQueriesService);

impl WithServiceAbi for GraphQlQueriesService {
type Abi = GraphQlQueriesAbi;
}

impl Service for GraphQlQueriesService {
type Parameters = ();

async fn new(runtime: ServiceRuntime<Self>) -> Self {
let state = GraphQlQueriesState::load(runtime.root_view_storage_context())
.await
.expect("Failed to load state");
GraphQlQueriesService {
state: Arc::new(state),
runtime: Arc::new(runtime),
}
}

async fn handle_query(&self, request: Request) -> Response {
let schema = Schema::build(
self.state.clone(),
GraphQlQueriesOperation::mutation_root(self.runtime.clone()),
EmptySubscription,
)
.finish();
schema.execute(request).await
}
}
16 changes: 16 additions & 0 deletions linera-sdk/tests/fixtures/graph-ql-queries/src/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Zefchain Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use linera_sdk::views::{
linera_views, CollectionView, MapView, RegisterView, RootView, ViewStorageContext,
};

/// The application state.
#[derive(RootView, async_graphql::SimpleObject)]
#[view(context = ViewStorageContext)]
pub struct GraphQlQueriesState {
pub reg: RegisterView<u64>,
pub map_s: MapView<String, u8>,
pub coll_s: CollectionView<String, RegisterView<u8>>,
pub coll_map: CollectionView<String, MapView<String, u64>>,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) Zefchain Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! Integration tests for the Matching Engine application
#![cfg(not(target_arch = "wasm32"))]

use graph_ql_queries::{GraphQlQueriesAbi, GraphQlQueriesOperation};
use linera_sdk::test::{QueryOutcome, TestValidator};

#[tokio::test]
async fn test_queries() {
let (validator, module_id) =
TestValidator::with_current_module::<GraphQlQueriesAbi, (), ()>().await;

let mut chain = validator.new_chain().await;

let application_id = chain.create_application(module_id, (), (), vec![]).await;

let operation1 = GraphQlQueriesOperation::SetRegister { value: 124 };
let operation2 = GraphQlQueriesOperation::InsertMapString {
key: "a".into(),
value: 91,
};
let operation3 = GraphQlQueriesOperation::InsertCollString {
key: "a".into(),
value: 91,
};
let operation4 = GraphQlQueriesOperation::InsertCollMap {
key1: "A".into(),
key2: "X".into(),
value: 49,
};

chain
.add_block(|block| {
block
.with_operation(application_id, operation1)
.with_operation(application_id, operation2)
.with_operation(application_id, operation3)
.with_operation(application_id, operation4);
})
.await;

// READ1

for (query, expected_response) in [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to use insta here (with the snapshot identifier being the query).

("reg", "{\"reg\":124}"),
("mapS { keys }", "{\"mapS\":{\"keys\":[\"a\"]}}"),
("mapS { entry(key: \"a\") { key, value } }", "{\"mapS\":{\"entry\":{\"key\":\"a\",\"value\":91}}}"),
("mapS { entries { key, value } }", "{\"mapS\":{\"entries\":[{\"key\":\"a\",\"value\":91}]}}"),
("mapS { entries(input: {}) { key, value } }", "{\"mapS\":{\"entries\":[{\"key\":\"a\",\"value\":91}]}}"),
("mapS { entries(input: { filters: {} }) { key, value } }", "{\"mapS\":{\"entries\":[{\"key\":\"a\",\"value\":91}]}}"),
("mapS { entries(input: { filters: { keys: [\"a\"]} }) { key, value } }", "{\"mapS\":{\"entries\":[{\"key\":\"a\",\"value\":91}]}}"),
("mapS { entries(input: { filters: { keys: [\"b\"]} }) { key, value } }", "{\"mapS\":{\"entries\":[{\"key\":\"b\",\"value\":null}]}}"),
("mapS { count }", "{\"mapS\":{\"count\":1}}"),
("collS { keys }", "{\"collS\":{\"keys\":[\"a\"]}}"),
("collS { entry(key: \"a\") { key, value } }", "{\"collS\":{\"entry\":{\"key\":\"a\",\"value\":91}}}"),
("collS { entries { key, value } }", "{\"collS\":{\"entries\":[{\"key\":\"a\",\"value\":91}]}}"),
("collS { entries(input: {}) { key, value } }", "{\"collS\":{\"entries\":[{\"key\":\"a\",\"value\":91}]}}"),
("collS { entries(input: { filters: {} }) { key, value } }", "{\"collS\":{\"entries\":[{\"key\":\"a\",\"value\":91}]}}"),
("collS { entries(input: { filters: { keys: [\"a\"]} }) { key, value } }", "{\"collS\":{\"entries\":[{\"key\":\"a\",\"value\":91}]}}"),
("collS { entries(input: { filters: { keys: [\"b\"]} }) { key, value } }", "{\"collS\":{\"entries\":[{\"key\":\"b\",\"value\":null}]}}"),
("collS { count }", "{\"collS\":{\"count\":1}}"),
("collMap { keys }", "{\"collMap\":{\"keys\":[\"A\"]}}"),
("collMap { entries { key, value { count } } }", "{\"collMap\":{\"entries\":[{\"key\":\"A\",\"value\":{\"count\":1}}]}}"),
("collMap { count }", "{\"collMap\":{\"count\":1}}"),
("collMap { entry(key: \"A\") { key, value { count } } }", "{\"collMap\":{\"entry\":{\"key\":\"A\",\"value\":{\"count\":1}}}}"),
("collMap { entry(key: \"B\") { key, value { count } } }", "{\"collMap\":{\"entry\":{\"key\":\"B\",\"value\":null}}}"),
("collMap { entry(key: \"A\") { key, value { entries(input: {}) { key, value } } } }",
"{\"collMap\":{\"entry\":{\"key\":\"A\",\"value\":{\"entries\":[{\"key\":\"X\",\"value\":49}]}}}}"),
("collMap { entries(input: {}) { key, value { count } } }",
"{\"collMap\":{\"entries\":[{\"key\":\"A\",\"value\":{\"count\":1}}]}}"),
("collMap { entries(input: {}) { key, value { entries(input: {}) { key, value } } } }",
"{\"collMap\":{\"entries\":[{\"key\":\"A\",\"value\":{\"entries\":[{\"key\":\"X\",\"value\":49}]}}]}}"),
("collMap { entries { key, value { keys } } }",
"{\"collMap\":{\"entries\":[{\"key\":\"A\",\"value\":{\"keys\":[\"X\"]}}]}}"),
("collMap { entries(input: {}) { key, value { keys } } }",
"{\"collMap\":{\"entries\":[{\"key\":\"A\",\"value\":{\"keys\":[\"X\"]}}]}}"),
("collMap { entries(input: { filters: {} }) { key, value { keys } } }",
"{\"collMap\":{\"entries\":[{\"key\":\"A\",\"value\":{\"keys\":[\"X\"]}}]}}"),
("collMap { entries(input: { filters: { keys: [\"A\"] } }) { key, value { keys } } }",
"{\"collMap\":{\"entries\":[{\"key\":\"A\",\"value\":{\"keys\":[\"X\"]}}]}}"),
("collMap { entries(input: { filters: { keys: [\"B\"] } }) { key, value { keys } } }",
"{\"collMap\":{\"entries\":[{\"key\":\"B\",\"value\":null}]}}"),
] {
println!("query={}", query);
let new_query = format!("query {{ {} }}", query);
let QueryOutcome { response, .. } = chain.graphql_query(application_id, new_query).await;
println!("expected_response={expected_response}");
println!("response={response}");
assert_eq!(format!("{response}"), expected_response);
println!();
}
}
Loading
Loading