Fix mocking multiple http calls in the same function call (#6510)

* Fix mocking multiple http calls in the same function call

Fixes an issue where a function call would perform more than one http request and wait for each to complete before proceeding. The `RequestId` comes from the length of the `requests` collection in the `OffchainState` and if a request is completed before the next one starts it will be removed and the "next expected" will be off by one. This PR tries to fix that by using a request counter that tracks how many requests have been performed so that we can `remove()` items from the `expected_requests` at the right index.

I suspect that this is a sub-optimal soluton and perhaps requests and their mocks should live side by side in the same collection, e.g. in a tuple of `(PendingRequest, Option<ExpectedRequest>)`.

* Update primitives/core/src/offchain/testing.rs

Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>

* Update primitives/core/src/offchain/testing.rs

Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>

* Panic on overflow

* Update primitives/core/src/offchain/testing.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Use a Deque and push/pop expected requests

* fix test

Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
David
2020-07-01 10:22:47 +02:00
committed by GitHub
parent ce02e1df84
commit d73de3bed7
3 changed files with 56 additions and 10 deletions
@@ -21,7 +21,7 @@
//! the extra APIs.
use std::{
collections::BTreeMap,
collections::{BTreeMap, VecDeque},
sync::Arc,
};
use crate::offchain::{
@@ -120,7 +120,8 @@ impl OffchainStorage for TestPersistentOffchainDB {
pub struct OffchainState {
/// A list of pending requests.
pub requests: BTreeMap<RequestId, PendingRequest>,
expected_requests: BTreeMap<RequestId, PendingRequest>,
// Queue of requests that the test is expected to perform (in order).
expected_requests: VecDeque<PendingRequest>,
/// Persistent local storage
pub persistent_storage: TestPersistentOffchainDB,
/// Local storage
@@ -156,8 +157,8 @@ impl OffchainState {
}
fn fulfill_expected(&mut self, id: u16) {
if let Some(mut req) = self.expected_requests.remove(&RequestId(id)) {
let response = req.response.take().expect("Response checked while added.");
if let Some(mut req) = self.expected_requests.pop_back() {
let response = req.response.take().expect("Response checked when added.");
let headers = std::mem::take(&mut req.response_headers);
self.fulfill_pending_request(id, req, response, headers);
}
@@ -169,11 +170,12 @@ impl OffchainState {
/// before running the actual code that utilizes them (for instance before calling into runtime).
/// Expected request has to be fulfilled before this struct is dropped,
/// the `response` and `response_headers` fields will be used to return results to the callers.
pub fn expect_request(&mut self, id: u16, expected: PendingRequest) {
/// Requests are expected to be performed in the insertion order.
pub fn expect_request(&mut self, expected: PendingRequest) {
if expected.response.is_none() {
panic!("Expected request needs to have a response.");
}
self.expected_requests.insert(RequestId(id), expected);
self.expected_requests.push_front(expected);
}
}