Skip to content

Commit

Permalink
Add unit tests for RPCHistory
Browse files Browse the repository at this point in the history
  • Loading branch information
André Vants committed Jul 29, 2022
1 parent 48390fd commit 4fd874a
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 8 deletions.
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ let package = Package(
dependencies: ["WalletConnectKMS", "WalletConnectUtils", "TestingUtils"]),
.target(
name: "TestingUtils",
dependencies: ["WalletConnectUtils", "WalletConnectKMS"],
dependencies: ["WalletConnectUtils", "WalletConnectKMS", "JSONRPC"],
path: "Tests/TestingUtils"),
.testTarget(
name: "WalletConnectUtilsTests",
dependencies: ["WalletConnectUtils"]),
dependencies: ["WalletConnectUtils", "JSONRPC", "TestingUtils"]),
.testTarget(
name: "JSONRPCTests",
dependencies: ["JSONRPC", "TestingUtils"]),
Expand Down
12 changes: 12 additions & 0 deletions Sources/Commons/Either.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,15 @@ extension Either: Codable where L: Codable, R: Codable {
}
}
}

extension Either: CustomStringConvertible {

public var description: String {
switch self {
case let .left(left):
return "\(left)"
case let .right(right):
return "\(right)"
}
}
}
4 changes: 2 additions & 2 deletions Sources/JSONRPC/RPCRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ public struct RPCRequest: Equatable {

extension RPCRequest {

static func notification<C>(method: String, params: C) -> RPCRequest where C: Codable {
public static func notification<C>(method: String, params: C) -> RPCRequest where C: Codable {
return RPCRequest(method: method, params: AnyCodable(params), id: nil)
}

static func notification(method: String) -> RPCRequest {
public static func notification(method: String) -> RPCRequest {
return RPCRequest(method: method, params: nil, id: nil)
}

Expand Down
4 changes: 4 additions & 0 deletions Sources/JSONRPC/RPCResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ public struct RPCResponse: Equatable {
self.init(id: matchingRequest.id, outcome: .success(AnyCodable(result)))
}

public init(matchingRequest: RPCRequest, error: JSONRPCError) {
self.init(id: matchingRequest.id, outcome: .failure(error))
}

public init<C>(id: Int, result: C) where C: Codable {
self.init(id: RPCID(id), outcome: .success(AnyCodable(result)))
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/WalletConnectRelay/RelayClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public final class RelayClient {
.wrapToIridium()
.asRPCRequest()
let message = try! request.asJSONEncodedString()
rpcHistory.delete(topic: topic)
rpcHistory.deleteAll(forTopic: topic)
var cancellable: AnyCancellable?
cancellable = requestAcknowledgePublisher
.filter { $0 == request.id }
Expand All @@ -225,7 +225,7 @@ public final class RelayClient {
if let request = tryDecode(RPCRequest.self, from: payload) {
if let params = try? request.params?.get(Subscription.Params.self) {
do {
try rpcHistory.set(request, for: params.data.topic, emmitedBy: .remote)
try rpcHistory.set(request, forTopic: params.data.topic, emmitedBy: .remote)
try acknowledgeRequest(request)
onMessage?(params.data.topic, params.data.message)
} catch {
Expand Down
4 changes: 2 additions & 2 deletions Sources/WalletConnectUtils/RPCHistory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public final class RPCHistory {
try? storage.get(key: "\(recordId)")
}

public func set(_ request: RPCRequest, for topic: String, emmitedBy origin: Record.Origin) throws {
public func set(_ request: RPCRequest, forTopic topic: String, emmitedBy origin: Record.Origin) throws {
guard let id = request.id else {
throw HistoryError.unidentifiedRequest
}
Expand All @@ -57,7 +57,7 @@ public final class RPCHistory {
storage.set(record, forKey: "\(record.id)")
}

public func delete(topic: String) {
public func deleteAll(forTopic topic: String) {
storage.getAll().forEach { record in
if record.topic == topic {
storage.delete(forKey: "\(record.id)")
Expand Down
12 changes: 12 additions & 0 deletions Tests/TestingUtils/Mocks/RPC.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import JSONRPC

public extension RPCRequest {

static func stub() -> RPCRequest {
RPCRequest(method: "method", params: EmptyCodable())
}

static func stub(method: String, id: Int) -> RPCRequest {
RPCRequest(method: method, params: EmptyCodable(), id: id)
}
}
110 changes: 110 additions & 0 deletions Tests/WalletConnectUtilsTests/RPCHistoryTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import XCTest
import JSONRPC
import TestingUtils
@testable import WalletConnectUtils

final class RPCHistoryTests: XCTestCase {

var sut: RPCHistory!

override func setUp() {
let storage = CodableStore<RPCHistory.Record>(defaults: RuntimeKeyValueStorage(), identifier: "")
sut = RPCHistory(keyValueStore: storage)
}

override func tearDown() {
sut = nil
}

// MARK: History Storage Tests

func testRoundTrip() throws {
let request = RPCRequest.stub()
try sut.set(request, forTopic: String.randomTopic(), emmitedBy: .local)
let record = sut.get(recordId: request.id!)
XCTAssertNil(record?.response)
XCTAssertEqual(record?.request, request)
}

func testResolveSuccessAndError() throws {
let requestA = RPCRequest.stub()
let requestB = RPCRequest.stub()
let responseA = RPCResponse(matchingRequest: requestA, result: true)
let responseB = RPCResponse(matchingRequest: requestB, error: .internalError)
try sut.set(requestA, forTopic: String.randomTopic(), emmitedBy: .remote)
try sut.set(requestB, forTopic: String.randomTopic(), emmitedBy: .local)
try sut.resolve(responseA)
try sut.resolve(responseB)
let recordA = sut.get(recordId: requestA.id!)
let recordB = sut.get(recordId: requestB.id!)
XCTAssertEqual(recordA?.response, responseA)
XCTAssertEqual(recordB?.response, responseB)
}

func testDelete() throws {
let requests = (1...5).map { _ in RPCRequest.stub() }
let topic = String.randomTopic()
try requests.forEach { try sut.set($0, forTopic: topic, emmitedBy: .local) }
sut.deleteAll(forTopic: topic)
requests.forEach {
XCTAssertNil(sut.get(recordId: $0.id!))
}
}

// MARK: Error Cases Tests

func testSetUnidentifiedRequest() {
let expectedError = RPCHistory.HistoryError.unidentifiedRequest

let request = RPCRequest.notification(method: "notify")
XCTAssertThrowsError(try sut.set(request, forTopic: String.randomTopic(), emmitedBy: .local)) { error in
XCTAssertEqual(expectedError, error as? RPCHistory.HistoryError)
}
}

func testSetDuplicateRequest() throws {
let expectedError = RPCHistory.HistoryError.requestDuplicateNotAllowed

let id = Int.random()
let requestA = RPCRequest.stub(method: "method-1", id: id)
let requestB = RPCRequest.stub(method: "method-2", id: id)
let topic = String.randomTopic()

try sut.set(requestA, forTopic: topic, emmitedBy: .local)
XCTAssertThrowsError(try sut.set(requestB, forTopic: topic, emmitedBy: .local)) { error in
XCTAssertEqual(expectedError, error as? RPCHistory.HistoryError)
}
}

func testResolveResponseWithoutRequest() throws {
let expectedError = RPCHistory.HistoryError.requestMatchingResponseNotFound

let response = RPCResponse(id: 0, result: true)
XCTAssertThrowsError(try sut.resolve(response)) { error in
XCTAssertEqual(expectedError, error as? RPCHistory.HistoryError)
}
}

func testResolveUnidentifiedResponse() throws {
let expectedError = RPCHistory.HistoryError.unidentifiedResponse

let response = RPCResponse(errorWithoutID: JSONRPCError.internalError)
XCTAssertThrowsError(try sut.resolve(response)) { error in
XCTAssertEqual(expectedError, error as? RPCHistory.HistoryError)
}
}

func testResolveDuplicateResponse() throws {
let expectedError = RPCHistory.HistoryError.responseDuplicateNotAllowed

let request = RPCRequest.stub()
let responseA = RPCResponse(matchingRequest: request, result: true)
let responseB = RPCResponse(matchingRequest: request, result: false)

try sut.set(request, forTopic: String.randomTopic(), emmitedBy: .local)
try sut.resolve(responseA)
XCTAssertThrowsError(try sut.resolve(responseB)) { error in
XCTAssertEqual(expectedError, error as? RPCHistory.HistoryError)
}
}
}

0 comments on commit 4fd874a

Please sign in to comment.