Async Testing
• Mark Eschbach
At this point I’m seeing some interesting behavior from CocoaAsyncSocket’s and it’s usage of the underlying asynchronus APIs. The client is not buffering writes prior to connection. When placing a poor man’s unbound buffer for writing to wait for the connection, I still had no luck. I’m wondering if there is an exception hook I’m missing somewhere. So checking assumptions by putting in a delay the outbound data is written in full within 10 seconds and properly read by the idealing service.
So my new hyptohesis is I’m synchronizing on the wrong set of events. Pulling out my hacky buffering confirms the data isn’t being discarded before the socket has been successfully established; good…I wasn’t looking forward to maintaining the state. I’ve confirmed the library will await all pending writes in source. Interestingly enough though, in the actual source it will not await for the queue to be fully drained. Reading through some of the source (it’s a big file) of GCDAsyncSocket it definitely appears as though the underlying queue is expected to be synchronous. Let’s chase this assumption down. The current implementation is using the main queue. Conceptually the following sequence of events occur with this test related to the client:
- Test begins execution
- The client socket connection is enqueued
- Log message is enqueue
- Close operation is enqueue
- Wait expectation is enqueued (I’m assuming)
- Connection established and dequeues writes
- Write messages complete
- CLose operation is dequeued
- Expectations are completed
I seem to have two major assumptions: the main dispatch queue in OSX is run synchronously; and the expectation operation doesn’t block the dispatch queue. Reading through the Apple’s docs on the main queue it’s a serially dispatched. Taking that at face value I’m wondering what the implementation of the wait expectation is. I think this is unlikely because a blocking sleep
operation will allow the test to complete succesfully but at this point I’m curious. Oh man, I still had a sleep(5)
in there :-/. Alright. Time to explore more about the synchronization timeouts. According to waitForExpectations
docs it should continue execute tasks off the main queue.
At this point I’m going to assume I’m not using the expectation waiting system correctly. I’m guessin the waitForExpectations
block is being called immediately. To test this I’m going to print a high resolution timestamp before the the method is called and in the block. If they are not close enough then I’m going to assume the timeout is not being honored. Confirmed the methods are actually called in the correct order but it’s not flushed.
So I spun off the testing socket and delegate methods into their own queues, just using default serial queues for each. This seems to deterministiclly work, so I’m assuming there was a strange interaction with the main queue I don’t queit understand. Either way, time to commit and move forward.
Next up in the prewritten tests are dealing with TLS. I’m not sure how to deal with generating the key pairs or how to establish the service socket. So I’m going to cheat and punt on working with it right now.
Moving on to the UDP sockets. This is outside of the scope of the project I’m actually working on. I think I need to go through a clean up phase at this point. Done.
Working on continous integration via Travis CI. I alaways forget the stanzas for this. Should be a lot simplier than our production system though since it isn’t concerned with release management. Ideally I would be able to build against a number of OSX images, but for now I’ll settle on XCode 8.1. Well that is slightly annoying: I can’t add the public repository because TravisCI doesn’t seem me as apart of an organziation :-/. Strange; worked around it by having the organization manually add the repository. I think I may have broken Travis’s requests unit. All well.
Onto figuring out how to publish the Pod! This should be interesting. The official documentation looks like it might lead me down the correct path. AAANND the project I inherited looks like it didn’t use the gneerator for pods. This conversion will be very interesting. Alrighty, so I think I’m going to try to see if the pod lib
tool is able to create a pod from an existing project. Nope, retrofiting the project it is.
Overall I kept the .podspec
file and modified the .travis.yml
file. I’m hoping this works. Trying to verify the qaulity via pod lib lint
. Simple fix to which files are actually apart of the source and it passes. Now to attempt to recreate the example application for quality assurance purproses. Hmm, I keep getting the error “A build only device cannot be used to run this target.” I’m assuming this has something to do with targeting iOS only. Yup, fixed with -destination 'platform=iOS Simulator,name=iPhone 6,OS=9.3'
!
Now to integrate the project into our primary iOS application! Time to modify the Pod. Well that was less painful than I thought it could be. Now on to modifying the logger to provide better lifecycle and clean up the API. And I opened the project file again. I really need to remember to open the workspace when dealing with pods.