justeat / shock Goto Github PK
View Code? Open in Web Editor NEWA HTTP mocking framework written in Swift.
Home Page: https://www.just-eat.com/
License: Apache License 2.0
A HTTP mocking framework written in Swift.
Home Page: https://www.just-eat.com/
License: Apache License 2.0
The current Shock version (6.1.1) relies on swift-nio version 2.38 which has following issue: apple/swift-nio#2073
The issue causes compilation error on Xcode 13.3 in release mode, making Shock unusable in my UITests target.
Version 6.0 doesn't have that issue but it cannot be used with Xcode older than 13.3
I can see on master branch that swift-nio version has been already upgraded to 2.40 which contains a fix for above mentioned issue.
(1b4013b)
So I guess all we need to do is to release a new version of Shock ๐
The new version should fix my problem (already tested it basing on master branch source)
Hello JustEat team, for start i would like to thank you for the effort you put on creating Shock. Great job.
I started using it, it is great however i'm currently having a problem.
I have set of basic routes that i add before starting the mock server in the tests setUp
function of XCTest
subclass.
Then sometimes when executing test function i want to add more routes that are related to that particular test. To do that i use the same setup(route:
function on the same MockServer
instance. The problem is that those added mocks are not working.
I have modified the MockNIOHTTPRouter
to produce logs:
struct MockNIOHTTPRouter: MockHttpRouter {
private var routes = [MockHTTPMethod: [RouteHandlerMapping]]()
var requiresRouteMiddleware: Bool {
!routes.isEmpty
}
func handlerForMethod(_ method: String, path: String, params: [String:String], headers: [String:String]) -> HandlerClosure? {
print("MockServer.handler: \(method) \(path) \(params)")
guard let httpMethod = MockHTTPMethod(rawValue: method.uppercased()) else { return nil }
let methodRoutes = routes[httpMethod] ?? [RouteHandlerMapping]()
print("MockServer.handler.methodRoutes: \(routes[httpMethod]!.map { "\($0.route.method!) \($0.route.urlPath!)" })")
for mapping in methodRoutes {
if mapping.route.matches(method: httpMethod, path: path, params: params, headers: headers) {
print("MockServer.handler: found handler")
return mapping.handler
}
}
print("MockServer.handler: not found handler")
return nil
}
mutating func register(route: MockHTTPRoute, handler: HandlerClosure?) {
print("MockServer.register: \(route.method!) \(route.urlPath!)")
guard let method = route.method else { return }
var methodRoutes = routes[method] ?? [RouteHandlerMapping]()
if methodRoutes.contains() { $0.route == route } {
methodRoutes = methodRoutes.filter({ $0.route != route })
}
if let handler = handler {
methodRoutes.append(RouteHandlerMapping(route: route, handler: handler))
}
routes[method] = methodRoutes
print("MockServer.register.methodRoutes: \(routes[method]!.map { "\($0.route.method!) \($0.route.urlPath!)" })")
}
}
here are the relevant logs:
MockServer.register: post /api/v2/verification/register
MockServer.register.methodRoutes: ["post /api/v2/app/app_update", "post /api/v2/app/boot", "post /api/v2/verification/register"]
MockServer.handler: POST /api/v2/verification/register [:]
MockServer.handler.methodRoutes: ["post /api/v2/app/app_update", "post /api/v2/app/boot"]
MockServer.handler: not found handler
It looks like routes dictionary is missing the route i have just added, but the old ones are there. I tried to replicate my problem in the example app from the Shock repo, but it works properly there. For me the root cause remains unknown.
I spent some time debugging it and trying to fix it, but so far the only way to make that problem go away is just changing the
MockNIOHTTPRouter
to be class instead of a struct.
Maybe you will be able to understand fully the root cause and fix in a different way rather than doing the change i mentioned.
We use Carthage for dependency management, I get this error when I try to install Shock
*** Skipped building Shock due to the error:
Dependency "Shock" has no shared framework schemes
Placeholder issue for supporting multiple mock servers when running parallel UI tests. Please keep any discussion on this ticket.
Multiple request handlers firing at the same time can cause various middleware to be executed on different threads (per request). We should allow a queue to be specified for running closure middleware to avoid obscure threading issues, such as accessing shared resources.
Hi there, thanks for creating a fantastic framework for UI test.
I feel like there are some cases we might need to verify the app's behaviour when the network is slow, could we please add latency
to support that?
It's quite similar to the timeout
case in MockHTTPRoute
. If you guys are busy, I could raise an MR to do that as well.
Thank you again and keep up the good work!
Hey,
First of all - thanks for supporting and maintaining this project :).
We've realised that since shock v6.0.2, our build fails both locally and on our CI:
Compiling MockNIOHTTPServer.swift
โ /Users/distiller/Library/Developer/Xcode/DerivedData/my-project-dqbgazaxqnczfdfghkppaziypfgm/SourcePackages/checkouts/Shock/Shock/Classes/Middleware/Middleware.swift:25:23: cannot find type 'Data' in scope
var responseBody: Data? { get set
Do you have any idea, what the root cause could be ?
The only thing that I've noticed is that you're now importing NIO instead of fundation:
2ce5878#diff-eaf72a9a43c823164559e08e249874c845f0d4fb28d7d801b97c8e64abe7e1efR8
Thank you.
In my UI test, I would need to change some response in runtime of the server, meaning calling setup(...) again. It looks like the MockHTTPRoute conformance to Equatable protocol currently only checks for matching method and path in order to say they are equal, ignoring the template or body altogether and therefore, two seemingly different setup requests will be treated as equal and not being overwritten by the second one.
I feel like this conformance to Equatable doesn't represent the identity of the route accurately and should be updated to account for differences in the body as well. (different file name, different template info).
I could open a PR for that on my own, if there is enough interest in this feature.
I have some tests where i need to:
But after many days of debugging I cannot get this to work using routes. It probably would be possible with Middleware and that may be where I have to go.
I can tell you from many days of debugging that I can see the routes changing in the router instance on the server, but the server has an instance of MockNIOHTTPHandler that seems to point to an unaltered instance of the router. I have verified that the two instances are at different addresses, but not sure how that is possible because I have verified only the one router instance is created.
Oddly sometimes it works if I step through in the debugger
It would be really nice to have a possibility to distinguish different mocks not only by the request url and other params available for now, but also by body. That would allow to set mocks for same url but with different body. Could we get something like that sometimes in a while? Thanks!
Currently it's impossible to use the library with [[String: AnyHashable?]]
.
Currently the exact sets of query and header parameters must be provided to match the request.
If possible we should try and relax this requirement so that only specified query parameters and headers are matched, and any others are ignored.
I have problem as below:
In source code with URLSession:
var request = URLRequest(url:url)
request.httpMethod = "POST"
In test code:
let route = .simple(method:.post,urlPath:"/test",code:501,filename:"api_test.json")
mockServer.setup(route:route)
Then I run the test case the server respone with StatusCode = 0.
I debugging I found the strange:
In MockNIOHTTPServer
, func handlerForMethod(_:Path:params:headers)
MockHttpMethod(rawValue:method.uppercased())
return an invalid enum instance (0x06) even though method is "POST"
Sorry for my newbie in Swift. I can't understand the reason.
I cannot say this is definitely related to Shock, but in CI we get somewhat random crashes and you can see from the crash log that Shock is in the stack trace. This was with version 6.1.1:
Thread 13 Crashed:: NIO-ELT-94-#2
0 libswiftCore.dylib 0x18f2e9b44 _assertionFailure(_:_:file:line:flags:) + 608
1 libswiftCore.dylib 0x18f2e9b44 _assertionFailure(_:_:file:line:flags:) + 608
2 NIOCore 0x105b79ee4 EventLoop.preconditionInEventLoop(file:line:) + 216 (EventLoop.swift:770)
3 NIOPosix 0x10602e7c8 protocol witness for EventLoop.preconditionInEventLoop(file:line:) in conformance SelectableEventLoop + 16
4 NIOCore 0x105b797ec closure #1 in EventLoop.assertInEventLoop(file:line:) + 104 (EventLoop.swift:751)
5 NIOCore 0x105bc38c0 closure #1 in implicit closure #1 in debugOnly(_:) + 44 (Utilities.swift:45)
6 NIOCore 0x105bc3834 debugOnly(_:) + 88 (Utilities.swift:45)
7 NIOCore 0x105b75b44 EventLoop.assertInEventLoop(file:line:) + 172 (EventLoop.swift:750)
8 NIOCore 0x105b4b4c4 ChannelHandlerContext.invokeWriteAndFlush(_:promise:) + 144 (ChannelPipeline.swift:1785)
9 NIOCore 0x105b5162c ChannelHandlerContext.writeAndFlush(_:promise:) + 168 (ChannelPipeline.swift:1601)
10 Shock 0x105d634dc MockNIOHTTPHandler.handleResponse(forResponseContext:in:version:) + 1200 (MockNIOHTTPHandler.swift:99)
11 Shock 0x105d651cc closure #1 in MockNIOHTTPHandler.channelRead(context:data:) + 168 (MockNIOHTTPHandler.swift:150)
12 NIOCore 0x105b84a1c closure #1 in EventLoopFuture.whenSuccess(_:) + 588 (EventLoopFuture.swift:729)
13 NIOCore 0x105b81640 EventLoopFuture._addCallback(_:) + 660 (EventLoopFuture.swift:700)
14 NIOCore 0x105b8479c closure #1 in EventLoopFuture._whenComplete(_:) + 80 (EventLoopFuture.swift:710)
15 NIOPosix 0x10602c994 thunk for @escaping @callee_guaranteed () -> () + 20
16 NIOPosix 0x10602c9b4 thunk for @escaping @callee_guaranteed () -> (@out ()) + 20
17 NIOPosix 0x10602ca00 closure #4 in SelectableEventLoop.run() + 64 (SelectableEventLoop.swift:520)
18 NIOPosix 0x105fba7d8 thunk for @callee_guaranteed () -> (@error @owned Error) + 24
19 NIOPosix 0x10602f5b4 thunk for @callee_guaranteed () -> (@error @owned Error)partial apply + 32
20 NIOPosix 0x106026a8c closure #1 in withAutoReleasePool<A>(_:) + 48 (SelectableEventLoop.swift:25)
21 NIOPosix 0x106026af4 partial apply for closure #1 in withAutoReleasePool<A>(_:) + 44
22 libswiftObjectiveC.dylib 0x1b5f2af50 autoreleasepool<A>(invoking:) + 56
23 NIOPosix 0x106026a20 withAutoReleasePool<A>(_:) + 88 (SelectableEventLoop.swift:24)
24 NIOPosix 0x10602b298 SelectableEventLoop.run() + 2024 (SelectableEventLoop.swift:519)
25 NIOPosix 0x105ffb4d4 static MultiThreadedEventLoopGroup.runTheLoop(thread:parentGroup:canEventLoopBeShutdownIndividually:selectorFactory:initializer:_:) + 620 (MultiThreadedEventLoopGroup.swift:89)
26 NIOPosix 0x105ffba80 closure #1 in static MultiThreadedEventLoopGroup.setupThreadAndEventLoop(name:parentGroup:selectorFactory:initializer:) + 300 (MultiThreadedEventLoopGroup.swift:110)
27 NIOPosix 0x106001200 partial apply for closure #1 in static MultiThreadedEventLoopGroup.setupThreadAndEventLoop(name:parentGroup:selectorFactory:initializer:) + 64
28 NIOPosix 0x10605b5dc thunk for @escaping @callee_guaranteed (@guaranteed NIOThread) -> () + 24
29 NIOPosix 0x10605f9e4 closure #1 in static ThreadOpsPosix.run(handle:args:detachThread:) + 1068 (ThreadPosix.swift:105)
30 NIOPosix 0x10605faec @objc closure #1 in static ThreadOpsPosix.run(handle:args:detachThread:) + 12
31 libsystem_pthread.dylib 0x1c7fe16c8 _pthread_start + 116
32 libsystem_pthread.dylib 0x1c7fdc910 thread_start + 8
Hi, Is there any plan to support html mock ? We have a case where we expect html and javascript and we have listener to javascript action and on the basis of that we are doing navigation.
While using SPM, we've found two package dependencies (swift-nio and mustache) are imported via SSH meaning XCode needs visibility of personal Github tokens to clone these. It's causing some friction with new joiners to our team (& those with low technical skill). Is it possible to switch these dependencies to use HTTP URLs to avoid adding an additional manual step?
Thanks ๐
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.