{"action":"closed","number":47,"pull_request":{"url":"https://api.github.com/repos/Parsely/streamparse/pulls/47","id":18997027,"html_url":"https://github.com/Parsely/streamparse/pull/47","diff_url":"https://github.com/Parsely/streamparse/pull/47.diff","patch_url":"https://github.com/Parsely/streamparse/pull/47.patch","issue_url":"https://api.github.com/repos/Parsely/streamparse/issues/47","number":47,"state":"closed","locked":false,"title":"Re-organize tests to avoid shell processes (branch: feature/reorg_tests)","user":{"login":"kbourgoin","id":136574,"avatar_url":"https://avatars.githubusercontent.com/u/136574?v=3","gravatar_id":"","url":"https://api.github.com/users/kbourgoin","html_url":"https://github.com/kbourgoin","followers_url":"https://api.github.com/users/kbourgoin/followers","following_url":"https://api.github.com/users/kbourgoin/following{/other_user}","gists_url":"https://api.github.com/users/kbourgoin/gists{/gist_id}","starred_url":"https://api.github.com/users/kbourgoin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kbourgoin/subscriptions","organizations_url":"https://api.github.com/users/kbourgoin/orgs","repos_url":"https://api.github.com/users/kbourgoin/repos","events_url":"https://api.github.com/users/kbourgoin/events{/privacy}","received_events_url":"https://api.github.com/users/kbourgoin/received_events","type":"User","site_admin":false},"body":"I'm opening this test for a review of the approach, not because all the tests have been reorganized. If there's support for the ideas in here, then I'll finish it up and replace our current tests with this.\r\n\r\n## Overview\r\n\r\nRight now, our tests are a bit brittle, the barrier to entry for adding new tests is too high, and debugging failing tests, or gathering code coverage statistics is fairly difficult. This is by no means to say the current tests are *bad*. They work, they test things, and they aren't *too* hard to add new things to. I did this because I want adding new tests to be **stupid easy**. Everything that makes adding new tests easier to write and debug means that more and better tests will get written.\r\n\r\nTo do this, the big thing I wanted to do was remove the subprocess calls entirely. While they look like Storm, they aren't Storm, and they add a good bit of complication to the setup. For one, it makes using pdb to debug a test impossible, and the break in process space makes code coverage harder to collect.\r\n\r\nFinally, we didn't have true integration tests. True integration tests would integrate with Storm and verify that communication was successful. Instead, it integrated with a mock that we created that mimics Storm. Instead of using a subprocess to mock Storm, I'm opting for the mock library to mock individual components. The mock library is a common Python tool for testing that any contributor walking in will know. Using a common tool like that will remove the barrier or learning how our subprocess storm mock works, which makes writing tests that much easier.\r\n\r\n*Disclaimer: I've no idea how this will play with python3. Testing that will come later.*\r\n\r\n## Benefits\r\n\r\n* Easier debugging into running test processes\r\n* Significantly faster tests\r\n  * No process creation/teardown for every test\r\n* Simpler testing\r\n  * Use common mock tools instead of our own mock framework\r\n* Unit testing means more focused tests covering specific use cases\r\n\r\n## Next steps\r\n\r\nIf other people agree this is a good approach, I'll finish test coverage for the current streamparse version. @msukmanowsky has a large Pull Request coming in, so I'll wait until that's resolved and write all the necessary testing for what's there. Once that's complete, I'll hook up coveralls for streamparse to get code coverage stats. I don't know how useful they'll be, but I'm curious about it and it's integration with Travis-CI.","created_at":"2014-07-28T22:06:54Z","updated_at":"2015-04-14T14:40:18Z","closed_at":"2015-04-14T14:40:18Z","merged_at":"2015-04-14T14:40:17Z","merge_commit_sha":"11bd6911d479a5f489ffe36a1a2c95ef72c4d49b","assignee":null,"milestone":{"url":"https://api.github.com/repos/Parsely/streamparse/milestones/3","html_url":"https://github.com/Parsely/streamparse/milestones/v1.2","labels_url":"https://api.github.com/repos/Parsely/streamparse/milestones/3/labels","id":695145,"number":3,"title":"v1.2","description":"...far off for now...","creator":{"login":"amontalenti","id":40263,"avatar_url":"https://avatars.githubusercontent.com/u/40263?v=3","gravatar_id":"","url":"https://api.github.com/users/amontalenti","html_url":"https://github.com/amontalenti","followers_url":"https://api.github.com/users/amontalenti/followers","following_url":"https://api.github.com/users/amontalenti/following{/other_user}","gists_url":"https://api.github.com/users/amontalenti/gists{/gist_id}","starred_url":"https://api.github.com/users/amontalenti/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/amontalenti/subscriptions","organizations_url":"https://api.github.com/users/amontalenti/orgs","repos_url":"https://api.github.com/users/amontalenti/repos","events_url":"https://api.github.com/users/amontalenti/events{/privacy}","received_events_url":"https://api.github.com/users/amontalenti/received_events","type":"User","site_admin":false},"open_issues":16,"closed_issues":3,"state":"open","created_at":"2014-06-18T20:09:14Z","updated_at":"2015-04-14T14:40:18Z","due_on":"2015-04-24T04:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/Parsely/streamparse/pulls/47/commits","review_comments_url":"https://api.github.com/repos/Parsely/streamparse/pulls/47/comments","review_comment_url":"https://api.github.com/repos/Parsely/streamparse/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Parsely/streamparse/issues/47/comments","statuses_url":"https://api.github.com/repos/Parsely/streamparse/statuses/8e20ede1dbe92e1a9c9fcd3dfacff53640685a20","head":{"label":"Parsely:feature/reorg_tests","ref":"feature/reorg_tests","sha":"8e20ede1dbe92e1a9c9fcd3dfacff53640685a20","user":{"login":"Parsely","id":779641,"avatar_url":"https://avatars.githubusercontent.com/u/779641?v=3","gravatar_id":"","url":"https://api.github.com/users/Parsely","html_url":"https://github.com/Parsely","followers_url":"https://api.github.com/users/Parsely/followers","following_url":"https://api.github.com/users/Parsely/following{/other_user}","gists_url":"https://api.github.com/users/Parsely/gists{/gist_id}","starred_url":"https://api.github.com/users/Parsely/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Parsely/subscriptions","organizations_url":"https://api.github.com/users/Parsely/orgs","repos_url":"https://api.github.com/users/Parsely/repos","events_url":"https://api.github.com/users/Parsely/events{/privacy}","received_events_url":"https://api.github.com/users/Parsely/received_events","type":"Organization","site_admin":false},"repo":{"id":19387849,"name":"streamparse","full_name":"Parsely/streamparse","owner":{"login":"Parsely","id":779641,"avatar_url":"https://avatars.githubusercontent.com/u/779641?v=3","gravatar_id":"","url":"https://api.github.com/users/Parsely","html_url":"https://github.com/Parsely","followers_url":"https://api.github.com/users/Parsely/followers","following_url":"https://api.github.com/users/Parsely/following{/other_user}","gists_url":"https://api.github.com/users/Parsely/gists{/gist_id}","starred_url":"https://api.github.com/users/Parsely/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Parsely/subscriptions","organizations_url":"https://api.github.com/users/Parsely/orgs","repos_url":"https://api.github.com/users/Parsely/repos","events_url":"https://api.github.com/users/Parsely/events{/privacy}","received_events_url":"https://api.github.com/users/Parsely/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Parsely/streamparse","description":"streamparse lets you run Python code against real-time streams of data. Integrates with Apache Storm.","fork":false,"url":"https://api.github.com/repos/Parsely/streamparse","forks_url":"https://api.github.com/repos/Parsely/streamparse/forks","keys_url":"https://api.github.com/repos/Parsely/streamparse/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Parsely/streamparse/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Parsely/streamparse/teams","hooks_url":"https://api.github.com/repos/Parsely/streamparse/hooks","issue_events_url":"https://api.github.com/repos/Parsely/streamparse/issues/events{/number}","events_url":"https://api.github.com/repos/Parsely/streamparse/events","assignees_url":"https://api.github.com/repos/Parsely/streamparse/assignees{/user}","branches_url":"https://api.github.com/repos/Parsely/streamparse/branches{/branch}","tags_url":"https://api.github.com/repos/Parsely/streamparse/tags","blobs_url":"https://api.github.com/repos/Parsely/streamparse/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Parsely/streamparse/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Parsely/streamparse/git/refs{/sha}","trees_url":"https://api.github.com/repos/Parsely/streamparse/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Parsely/streamparse/statuses/{sha}","languages_url":"https://api.github.com/repos/Parsely/streamparse/languages","stargazers_url":"https://api.github.com/repos/Parsely/streamparse/stargazers","contributors_url":"https://api.github.com/repos/Parsely/streamparse/contributors","subscribers_url":"https://api.github.com/repos/Parsely/streamparse/subscribers","subscription_url":"https://api.github.com/repos/Parsely/streamparse/subscription","commits_url":"https://api.github.com/repos/Parsely/streamparse/commits{/sha}","git_commits_url":"https://api.github.com/repos/Parsely/streamparse/git/commits{/sha}","comments_url":"https://api.github.com/repos/Parsely/streamparse/comments{/number}","issue_comment_url":"https://api.github.com/repos/Parsely/streamparse/issues/comments{/number}","contents_url":"https://api.github.com/repos/Parsely/streamparse/contents/{+path}","compare_url":"https://api.github.com/repos/Parsely/streamparse/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Parsely/streamparse/merges","archive_url":"https://api.github.com/repos/Parsely/streamparse/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Parsely/streamparse/downloads","issues_url":"https://api.github.com/repos/Parsely/streamparse/issues{/number}","pulls_url":"https://api.github.com/repos/Parsely/streamparse/pulls{/number}","milestones_url":"https://api.github.com/repos/Parsely/streamparse/milestones{/number}","notifications_url":"https://api.github.com/repos/Parsely/streamparse/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Parsely/streamparse/labels{/name}","releases_url":"https://api.github.com/repos/Parsely/streamparse/releases{/id}","created_at":"2014-05-02T20:33:50Z","updated_at":"2015-04-14T06:28:51Z","pushed_at":"2015-04-14T14:40:17Z","git_url":"git://github.com/Parsely/streamparse.git","ssh_url":"git@github.com:Parsely/streamparse.git","clone_url":"https://github.com/Parsely/streamparse.git","svn_url":"https://github.com/Parsely/streamparse","homepage":"","size":5923,"stargazers_count":661,"watchers_count":661,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":74,"mirror_url":null,"open_issues_count":35,"forks":74,"open_issues":35,"watchers":661,"default_branch":"master"}},"base":{"label":"Parsely:master","ref":"master","sha":"7f71da64413c437f277e876153bc63c7bfb057c7","user":{"login":"Parsely","id":779641,"avatar_url":"https://avatars.githubusercontent.com/u/779641?v=3","gravatar_id":"","url":"https://api.github.com/users/Parsely","html_url":"https://github.com/Parsely","followers_url":"https://api.github.com/users/Parsely/followers","following_url":"https://api.github.com/users/Parsely/following{/other_user}","gists_url":"https://api.github.com/users/Parsely/gists{/gist_id}","starred_url":"https://api.github.com/users/Parsely/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Parsely/subscriptions","organizations_url":"https://api.github.com/users/Parsely/orgs","repos_url":"https://api.github.com/users/Parsely/repos","events_url":"https://api.github.com/users/Parsely/events{/privacy}","received_events_url":"https://api.github.com/users/Parsely/received_events","type":"Organization","site_admin":false},"repo":{"id":19387849,"name":"streamparse","full_name":"Parsely/streamparse","owner":{"login":"Parsely","id":779641,"avatar_url":"https://avatars.githubusercontent.com/u/779641?v=3","gravatar_id":"","url":"https://api.github.com/users/Parsely","html_url":"https://github.com/Parsely","followers_url":"https://api.github.com/users/Parsely/followers","following_url":"https://api.github.com/users/Parsely/following{/other_user}","gists_url":"https://api.github.com/users/Parsely/gists{/gist_id}","starred_url":"https://api.github.com/users/Parsely/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Parsely/subscriptions","organizations_url":"https://api.github.com/users/Parsely/orgs","repos_url":"https://api.github.com/users/Parsely/repos","events_url":"https://api.github.com/users/Parsely/events{/privacy}","received_events_url":"https://api.github.com/users/Parsely/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Parsely/streamparse","description":"streamparse lets you run Python code against real-time streams of data. Integrates with Apache Storm.","fork":false,"url":"https://api.github.com/repos/Parsely/streamparse","forks_url":"https://api.github.com/repos/Parsely/streamparse/forks","keys_url":"https://api.github.com/repos/Parsely/streamparse/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Parsely/streamparse/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Parsely/streamparse/teams","hooks_url":"https://api.github.com/repos/Parsely/streamparse/hooks","issue_events_url":"https://api.github.com/repos/Parsely/streamparse/issues/events{/number}","events_url":"https://api.github.com/repos/Parsely/streamparse/events","assignees_url":"https://api.github.com/repos/Parsely/streamparse/assignees{/user}","branches_url":"https://api.github.com/repos/Parsely/streamparse/branches{/branch}","tags_url":"https://api.github.com/repos/Parsely/streamparse/tags","blobs_url":"https://api.github.com/repos/Parsely/streamparse/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Parsely/streamparse/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Parsely/streamparse/git/refs{/sha}","trees_url":"https://api.github.com/repos/Parsely/streamparse/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Parsely/streamparse/statuses/{sha}","languages_url":"https://api.github.com/repos/Parsely/streamparse/languages","stargazers_url":"https://api.github.com/repos/Parsely/streamparse/stargazers","contributors_url":"https://api.github.com/repos/Parsely/streamparse/contributors","subscribers_url":"https://api.github.com/repos/Parsely/streamparse/subscribers","subscription_url":"https://api.github.com/repos/Parsely/streamparse/subscription","commits_url":"https://api.github.com/repos/Parsely/streamparse/commits{/sha}","git_commits_url":"https://api.github.com/repos/Parsely/streamparse/git/commits{/sha}","comments_url":"https://api.github.com/repos/Parsely/streamparse/comments{/number}","issue_comment_url":"https://api.github.com/repos/Parsely/streamparse/issues/comments{/number}","contents_url":"https://api.github.com/repos/Parsely/streamparse/contents/{+path}","compare_url":"https://api.github.com/repos/Parsely/streamparse/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Parsely/streamparse/merges","archive_url":"https://api.github.com/repos/Parsely/streamparse/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Parsely/streamparse/downloads","issues_url":"https://api.github.com/repos/Parsely/streamparse/issues{/number}","pulls_url":"https://api.github.com/repos/Parsely/streamparse/pulls{/number}","milestones_url":"https://api.github.com/repos/Parsely/streamparse/milestones{/number}","notifications_url":"https://api.github.com/repos/Parsely/streamparse/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Parsely/streamparse/labels{/name}","releases_url":"https://api.github.com/repos/Parsely/streamparse/releases{/id}","created_at":"2014-05-02T20:33:50Z","updated_at":"2015-04-14T06:28:51Z","pushed_at":"2015-04-14T14:40:17Z","git_url":"git://github.com/Parsely/streamparse.git","ssh_url":"git@github.com:Parsely/streamparse.git","clone_url":"https://github.com/Parsely/streamparse.git","svn_url":"https://github.com/Parsely/streamparse","homepage":"","size":5923,"stargazers_count":661,"watchers_count":661,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":74,"mirror_url":null,"open_issues_count":35,"forks":74,"open_issues":35,"watchers":661,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Parsely/streamparse/pulls/47"},"html":{"href":"https://github.com/Parsely/streamparse/pull/47"},"issue":{"href":"https://api.github.com/repos/Parsely/streamparse/issues/47"},"comments":{"href":"https://api.github.com/repos/Parsely/streamparse/issues/47/comments"},"review_comments":{"href":"https://api.github.com/repos/Parsely/streamparse/pulls/47/comments"},"review_comment":{"href":"https://api.github.com/repos/Parsely/streamparse/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Parsely/streamparse/pulls/47/commits"},"statuses":{"href":"https://api.github.com/repos/Parsely/streamparse/statuses/8e20ede1dbe92e1a9c9fcd3dfacff53640685a20"}},"merged":true,"mergeable":null,"mergeable_state":"unknown","merged_by":{"login":"dan-blanchard","id":976345,"avatar_url":"https://avatars.githubusercontent.com/u/976345?v=3","gravatar_id":"","url":"https://api.github.com/users/dan-blanchard","html_url":"https://github.com/dan-blanchard","followers_url":"https://api.github.com/users/dan-blanchard/followers","following_url":"https://api.github.com/users/dan-blanchard/following{/other_user}","gists_url":"https://api.github.com/users/dan-blanchard/gists{/gist_id}","starred_url":"https://api.github.com/users/dan-blanchard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dan-blanchard/subscriptions","organizations_url":"https://api.github.com/users/dan-blanchard/orgs","repos_url":"https://api.github.com/users/dan-blanchard/repos","events_url":"https://api.github.com/users/dan-blanchard/events{/privacy}","received_events_url":"https://api.github.com/users/dan-blanchard/received_events","type":"User","site_admin":false},"comments":22,"review_comments":21,"commits":26,"additions":748,"deletions":1216,"changed_files":24}}