{"action":"created","comment":{"url":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls/comments/57069284","id":57069284,"diff_hunk":"@@ -163,28 +167,113 @@\n            ms/stream->seq\n            doall))))\n \n+(defn ^:private make-fake-page\n+  \"Generates a fake page function. Give it the expected base path and a\n+   function to call with the current page number.\"\n+  [cb]\n+  (fn [client-id client-secret url]\n+    (is (= client-id \"lvh\"))\n+    (is (= client-secret \"hunter2\"))\n+    (let [parsed-url (u/url url)\n+          path (:path parsed-url)\n+          query (:query parsed-url)\n+          page-num (-> query\n+                       (get \"page\" \"0\")\n+                       Integer/parseInt)]\n+      (cb {:page-num page-num :path path}))))\n+\n+(defn fake-servers-page\n+  \"Pretends to be the servers list page results.\"\n+  [page-two-breaks]\n+  (make-fake-page (fn [{:keys [page-num path]}]\n+                    (is (= \"/v1/servers\" path))\n+                    (case page-num\n+                      0 {:servers [{:id \"server-id-1\"} {:id \"server-id-2\"}]\n+                         :pagination {:next (str @#'scans/base-servers-url \"?page=1\")}}\n+                      1 (if page-two-breaks\n+                          :cloudpassage-lib.core/fetch-error\n+                          {:servers [{:id \"server-id-3\"}]})))))\n+\n+(deftest list-servers!-tests\n+  (testing \"Returns all servers if paginated call is OK.\"\n+    (with-redefs [scans/get-page! (fake-servers-page false)]\n+      (let [server-stream (scans/list-servers! \"lvh\" \"hunter2\")\n+            id-list (map :id (ms/stream->seq server-stream))]\n+        (is (= [\"server-id-1\" \"server-id-2\" \"server-id-3\"] id-list))\n+        (is (ms/closed? server-stream)))))\n+  (testing \"If page 2 is bad, a partial list is returned.\"\n+    (with-redefs [scans/get-page! (fake-servers-page true)]\n+      (let [server-stream (scans/list-servers! \"lvh\" \"hunter2\")\n+            id-list (map :id (ms/stream->seq server-stream))]\n+        (is (= [\"server-id-1\" \"server-id-2\"] id-list))","path":"test/cloudpassage_lib/scans_test.clj","position":53,"original_position":53,"commit_id":"70279968685a4b8a91af3aa98450e918da554be9","original_commit_id":"70279968685a4b8a91af3aa98450e918da554be9","user":{"login":"ehashman","id":4706131,"avatar_url":"https://avatars.githubusercontent.com/u/4706131?v=3","gravatar_id":"","url":"https://api.github.com/users/ehashman","html_url":"https://github.com/ehashman","followers_url":"https://api.github.com/users/ehashman/followers","following_url":"https://api.github.com/users/ehashman/following{/other_user}","gists_url":"https://api.github.com/users/ehashman/gists{/gist_id}","starred_url":"https://api.github.com/users/ehashman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ehashman/subscriptions","organizations_url":"https://api.github.com/users/ehashman/orgs","repos_url":"https://api.github.com/users/ehashman/repos","events_url":"https://api.github.com/users/ehashman/events{/privacy}","received_events_url":"https://api.github.com/users/ehashman/received_events","type":"User","site_admin":false},"body":"Is this the behaviour we want? If we can't fetch all the pages, we won't be able to return a list of all the servers, so we probably want to throw an exception and die. I'm pretty sure that's what the code says we do, but it looks like we're not actually exercising that logic here.","created_at":"2016-03-22T21:08:05Z","updated_at":"2016-03-22T21:08:05Z","html_url":"https://github.com/RackSec/cloudpassage-lib/pull/30#discussion_r57069284","pull_request_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls/30","_links":{"self":{"href":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls/comments/57069284"},"html":{"href":"https://github.com/RackSec/cloudpassage-lib/pull/30#discussion_r57069284"},"pull_request":{"href":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls/30"}}},"pull_request":{"url":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls/30","id":63305852,"html_url":"https://github.com/RackSec/cloudpassage-lib/pull/30","diff_url":"https://github.com/RackSec/cloudpassage-lib/pull/30.diff","patch_url":"https://github.com/RackSec/cloudpassage-lib/pull/30.patch","issue_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/issues/30","number":30,"state":"open","locked":false,"title":"Change API calls used to get scan data","user":{"login":"TimSimpsonR","id":739360,"avatar_url":"https://avatars.githubusercontent.com/u/739360?v=3","gravatar_id":"","url":"https://api.github.com/users/TimSimpsonR","html_url":"https://github.com/TimSimpsonR","followers_url":"https://api.github.com/users/TimSimpsonR/followers","following_url":"https://api.github.com/users/TimSimpsonR/following{/other_user}","gists_url":"https://api.github.com/users/TimSimpsonR/gists{/gist_id}","starred_url":"https://api.github.com/users/TimSimpsonR/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/TimSimpsonR/subscriptions","organizations_url":"https://api.github.com/users/TimSimpsonR/orgs","repos_url":"https://api.github.com/users/TimSimpsonR/repos","events_url":"https://api.github.com/users/TimSimpsonR/events{/privacy}","received_events_url":"https://api.github.com/users/TimSimpsonR/received_events","type":"User","site_admin":false},"body":"Previously we've been using the scans API to fetch data by time to\r\ngenerate our report. This PR changes it to fetch the most recent\r\nscans for each server (aka host) which keeps us from having to\r\nuse large time periods in our query to make sure we get some data\r\nfor each server while also having to throw our duplicate info for\r\nany server which may appear.","created_at":"2016-03-17T23:00:15Z","updated_at":"2016-03-22T21:08:05Z","closed_at":null,"merged_at":null,"merge_commit_sha":"86373e91d44b9425b2c9962dad5503b28b9bca6c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls/30/commits","review_comments_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls/30/comments","review_comment_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls/comments{/number}","comments_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/issues/30/comments","statuses_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/statuses/70279968685a4b8a91af3aa98450e918da554be9","head":{"label":"TimSimpsonR:server-scans-2","ref":"server-scans-2","sha":"70279968685a4b8a91af3aa98450e918da554be9","user":{"login":"TimSimpsonR","id":739360,"avatar_url":"https://avatars.githubusercontent.com/u/739360?v=3","gravatar_id":"","url":"https://api.github.com/users/TimSimpsonR","html_url":"https://github.com/TimSimpsonR","followers_url":"https://api.github.com/users/TimSimpsonR/followers","following_url":"https://api.github.com/users/TimSimpsonR/following{/other_user}","gists_url":"https://api.github.com/users/TimSimpsonR/gists{/gist_id}","starred_url":"https://api.github.com/users/TimSimpsonR/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/TimSimpsonR/subscriptions","organizations_url":"https://api.github.com/users/TimSimpsonR/orgs","repos_url":"https://api.github.com/users/TimSimpsonR/repos","events_url":"https://api.github.com/users/TimSimpsonR/events{/privacy}","received_events_url":"https://api.github.com/users/TimSimpsonR/received_events","type":"User","site_admin":false},"repo":{"id":53699080,"name":"cloudpassage-lib","full_name":"TimSimpsonR/cloudpassage-lib","owner":{"login":"TimSimpsonR","id":739360,"avatar_url":"https://avatars.githubusercontent.com/u/739360?v=3","gravatar_id":"","url":"https://api.github.com/users/TimSimpsonR","html_url":"https://github.com/TimSimpsonR","followers_url":"https://api.github.com/users/TimSimpsonR/followers","following_url":"https://api.github.com/users/TimSimpsonR/following{/other_user}","gists_url":"https://api.github.com/users/TimSimpsonR/gists{/gist_id}","starred_url":"https://api.github.com/users/TimSimpsonR/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/TimSimpsonR/subscriptions","organizations_url":"https://api.github.com/users/TimSimpsonR/orgs","repos_url":"https://api.github.com/users/TimSimpsonR/repos","events_url":"https://api.github.com/users/TimSimpsonR/events{/privacy}","received_events_url":"https://api.github.com/users/TimSimpsonR/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/TimSimpsonR/cloudpassage-lib","description":"","fork":true,"url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib","forks_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/forks","keys_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/keys{/key_id}","collaborators_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/teams","hooks_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/hooks","issue_events_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/issues/events{/number}","events_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/events","assignees_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/assignees{/user}","branches_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/branches{/branch}","tags_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/tags","blobs_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/git/refs{/sha}","trees_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/git/trees{/sha}","statuses_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/statuses/{sha}","languages_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/languages","stargazers_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/stargazers","contributors_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/contributors","subscribers_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/subscribers","subscription_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/subscription","commits_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/commits{/sha}","git_commits_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/git/commits{/sha}","comments_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/comments{/number}","issue_comment_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/issues/comments{/number}","contents_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/contents/{+path}","compare_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/compare/{base}...{head}","merges_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/merges","archive_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/downloads","issues_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/issues{/number}","pulls_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/pulls{/number}","milestones_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/milestones{/number}","notifications_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/labels{/name}","releases_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/releases{/id}","deployments_url":"https://api.github.com/repos/TimSimpsonR/cloudpassage-lib/deployments","created_at":"2016-03-11T21:56:32Z","updated_at":"2016-03-11T21:56:32Z","pushed_at":"2016-03-22T18:55:43Z","git_url":"git://github.com/TimSimpsonR/cloudpassage-lib.git","ssh_url":"git@github.com:TimSimpsonR/cloudpassage-lib.git","clone_url":"https://github.com/TimSimpsonR/cloudpassage-lib.git","svn_url":"https://github.com/TimSimpsonR/cloudpassage-lib","homepage":null,"size":61,"stargazers_count":0,"watchers_count":0,"language":"Clojure","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"RackSec:master","ref":"master","sha":"076455190c3cd44c2a33a86d7a1fd4eb0997a215","user":{"login":"RackSec","id":12700871,"avatar_url":"https://avatars.githubusercontent.com/u/12700871?v=3","gravatar_id":"","url":"https://api.github.com/users/RackSec","html_url":"https://github.com/RackSec","followers_url":"https://api.github.com/users/RackSec/followers","following_url":"https://api.github.com/users/RackSec/following{/other_user}","gists_url":"https://api.github.com/users/RackSec/gists{/gist_id}","starred_url":"https://api.github.com/users/RackSec/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RackSec/subscriptions","organizations_url":"https://api.github.com/users/RackSec/orgs","repos_url":"https://api.github.com/users/RackSec/repos","events_url":"https://api.github.com/users/RackSec/events{/privacy}","received_events_url":"https://api.github.com/users/RackSec/received_events","type":"Organization","site_admin":false},"repo":{"id":53524228,"name":"cloudpassage-lib","full_name":"RackSec/cloudpassage-lib","owner":{"login":"RackSec","id":12700871,"avatar_url":"https://avatars.githubusercontent.com/u/12700871?v=3","gravatar_id":"","url":"https://api.github.com/users/RackSec","html_url":"https://github.com/RackSec","followers_url":"https://api.github.com/users/RackSec/followers","following_url":"https://api.github.com/users/RackSec/following{/other_user}","gists_url":"https://api.github.com/users/RackSec/gists{/gist_id}","starred_url":"https://api.github.com/users/RackSec/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RackSec/subscriptions","organizations_url":"https://api.github.com/users/RackSec/orgs","repos_url":"https://api.github.com/users/RackSec/repos","events_url":"https://api.github.com/users/RackSec/events{/privacy}","received_events_url":"https://api.github.com/users/RackSec/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/RackSec/cloudpassage-lib","description":"A Clojure library for interacting with CloudPassage APIs.","fork":false,"url":"https://api.github.com/repos/RackSec/cloudpassage-lib","forks_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/forks","keys_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/keys{/key_id}","collaborators_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/teams","hooks_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/hooks","issue_events_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/issues/events{/number}","events_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/events","assignees_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/assignees{/user}","branches_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/branches{/branch}","tags_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/tags","blobs_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/git/refs{/sha}","trees_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/git/trees{/sha}","statuses_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/statuses/{sha}","languages_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/languages","stargazers_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/stargazers","contributors_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/contributors","subscribers_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/subscribers","subscription_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/subscription","commits_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/commits{/sha}","git_commits_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/git/commits{/sha}","comments_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/comments{/number}","issue_comment_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/issues/comments{/number}","contents_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/contents/{+path}","compare_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/compare/{base}...{head}","merges_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/merges","archive_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/downloads","issues_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/issues{/number}","pulls_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls{/number}","milestones_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/milestones{/number}","notifications_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/labels{/name}","releases_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/releases{/id}","deployments_url":"https://api.github.com/repos/RackSec/cloudpassage-lib/deployments","created_at":"2016-03-09T19:08:35Z","updated_at":"2016-03-17T00:45:11Z","pushed_at":"2016-03-22T18:55:44Z","git_url":"git://github.com/RackSec/cloudpassage-lib.git","ssh_url":"git@github.com:RackSec/cloudpassage-lib.git","clone_url":"https://github.com/RackSec/cloudpassage-lib.git","svn_url":"https://github.com/RackSec/cloudpassage-lib","homepage":"","size":54,"stargazers_count":1,"watchers_count":1,"language":"Clojure","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4,"mirror_url":null,"open_issues_count":5,"forks":4,"open_issues":5,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls/30"},"html":{"href":"https://github.com/RackSec/cloudpassage-lib/pull/30"},"issue":{"href":"https://api.github.com/repos/RackSec/cloudpassage-lib/issues/30"},"comments":{"href":"https://api.github.com/repos/RackSec/cloudpassage-lib/issues/30/comments"},"review_comments":{"href":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls/30/comments"},"review_comment":{"href":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/RackSec/cloudpassage-lib/pulls/30/commits"},"statuses":{"href":"https://api.github.com/repos/RackSec/cloudpassage-lib/statuses/70279968685a4b8a91af3aa98450e918da554be9"}}}}