{"action":"created","comment":{"url":"https://api.github.com/repos/CSCfi/pebbles/pulls/comments/110880462","pull_request_review_id":32082193,"id":110880462,"diff_hunk":"@@ -2151,6 +2151,106 @@ def test_user_fetch_instance_usage_stats(self):\n             path='/api/v1/stats')\n         self.assertStatus(response, 403)\n \n+    def test_create_namespaced_data(self):\n+        response = self.make_authenticated_admin_request(\n+            method='POST',\n+            path='/api/v1/namespaced_keyvalues',\n+            data=json.dumps({'namespace': 'TestDriver', 'key': 'test_pool_vm_1', 'value': {\"attr\": \"val\"}})\n+        )\n+        self.assert_200(response)\n+\n+    def test_create_duplicate_namespaced_data(self):\n+        response = self.make_authenticated_admin_request(\n+            method='POST',\n+            path='/api/v1/namespaced_keyvalues',\n+            data=json.dumps({'namespace': 'TestDriver', 'key': 'test_pool_vm_2', 'value': {\"attr\": \"val\"}})\n+        )\n+        self.assert_200(response)\n+\n+        # The combination of namespace and key has to be unique\n+        response = self.make_authenticated_admin_request(\n+            method='POST',\n+            path='/api/v1/namespaced_keyvalues',\n+            data=json.dumps({'namespace': 'TestDriver', 'key': 'test_pool_vm_2', 'value': {\"attr\": \"new_val\"}})\n+        )\n+        self.assertStatus(response, 422)\n+\n+    def test_update_namespaced_data(self):\n+        ns = \"TestDriver\"\n+        key = \"pool_vm_test_3\"\n+        ns_kv = NamespacedKeyValue(ns, key)\n+        ns_kv.value = {'attr': 'val'}\n+        ts = 1000000000\n+        ns_kv.created_ts = ts\n+        ns_kv.updated_ts = ts\n+        db.session.add(ns_kv)\n+        db.session.commit()\n+\n+        response = self.make_authenticated_admin_request(\n+            method='PUT',\n+            path='/api/v1/namespaced_keyvalues/%s/%s' % (ns, key),\n+            data=json.dumps({'namespace': 'TestDriver', 'key': 'test_pool_1', 'value': {\"attr\": \"val\"}, 'updated_version_ts': ts})\n+        )\n+        self.assert_200(response)\n+\n+    def test_invalid_create_update_namespaced_data(self):\n+        response = self.make_authenticated_admin_request(\n+            method='POST',\n+            path='/api/v1/namespaced_keyvalues',\n+            data=json.dumps({'namespace': 'TestDriver', 'key': 0, 'value': {\"attr\": \"val\"}})\n+        )\n+        self.assertStatus(response, 422)\n+\n+        response = self.make_authenticated_admin_request(\n+            method='POST',\n+            path='/api/v1/namespaced_keyvalues',\n+            data=json.dumps({'namespace': '', 'key': 'test_pool_vm_4', 'value': {\"attr\": \"val\"}})\n+        )\n+        self.assertStatus(response, 422)\n+\n+        ns = \"TestDriver\"\n+        key = \"pool_vm_test_4\"\n+        ns_kv = NamespacedKeyValue(ns, key)\n+        ns_kv.value = {'attr': 'val'}\n+        ts = 1000000000\n+        ns_kv.created_ts = ts\n+        ns_kv.updated_ts = ts\n+        db.session.add(ns_kv)\n+        db.session.commit()\n+\n+        response = self.make_authenticated_admin_request(\n+            method='PUT',\n+            path='/api/v1/namespaced_keyvalues/%s/%s' % (ns, key),\n+            data=json.dumps({'namespace': 'TestDriver', 'key': 'test_pool_1', 'value': {\"attr\": \"val\"}, 'updated_version_ts': 'bogusx10'})\n+        )\n+        self.assertStatus(response, 422)\n+\n+    def test_concurrent_update_namespaced_data(self):\n+        namespace = \"TestDriver\"\n+        key = \"test_pool_vm_5\"\n+        namespace_keyvalue_obj = NamespacedKeyValue(namespace, key)\n+        namespace_keyvalue_obj.value = {'attribute': 'value'}\n+        ts = 1000000000\n+        namespace_keyvalue_obj.created_ts = ts\n+        namespace_keyvalue_obj.updated_ts = ts\n+        db.session.add(namespace_keyvalue_obj)\n+        db.session.commit()\n+\n+        response = self.make_authenticated_admin_request(\n+            method='PUT',\n+            path='/api/v1/namespaced_keyvalues/%s/%s' % (namespace, key),\n+            data=json.dumps({'namespace': namespace, 'key': key, 'value': {\"attr\": \"val\"}, 'updated_version_ts': ts})\n+        )\n+        self.assert_200(response)\n+\n+        # Concurrent Modification\n+        invalid_response = self.make_authenticated_admin_request(\n+            method='PUT',\n+            path='/api/v1/namespaced_keyvalues/%s/%s' % (namespace, key),\n+            data=json.dumps({'namespace': namespace, 'key': key, 'value': {\"another_attr\": \"another_val\"}, 'updated_version_ts': ts})\n+        )\n+        self.assertStatus(invalid_response, 409)","path":"pebbles/tests/test_flask_api.py","position":111,"original_position":111,"commit_id":"06ca64f3ab18082c86add51bf3ec9c0f1366853f","original_commit_id":"06ca64f3ab18082c86add51bf3ec9c0f1366853f","user":{"login":"apurva3000","id":6124928,"avatar_url":"https://avatars0.githubusercontent.com/u/6124928?v=3","gravatar_id":"","url":"https://api.github.com/users/apurva3000","html_url":"https://github.com/apurva3000","followers_url":"https://api.github.com/users/apurva3000/followers","following_url":"https://api.github.com/users/apurva3000/following{/other_user}","gists_url":"https://api.github.com/users/apurva3000/gists{/gist_id}","starred_url":"https://api.github.com/users/apurva3000/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apurva3000/subscriptions","organizations_url":"https://api.github.com/users/apurva3000/orgs","repos_url":"https://api.github.com/users/apurva3000/repos","events_url":"https://api.github.com/users/apurva3000/events{/privacy}","received_events_url":"https://api.github.com/users/apurva3000/received_events","type":"User","site_admin":false},"body":"Good point, but they are practically everywhere in the tests, cannot change them all in this commit at least, can do as a part of general re-factoring later","created_at":"2017-04-11T11:46:13Z","updated_at":"2017-04-11T11:46:13Z","html_url":"https://github.com/CSCfi/pebbles/pull/596#discussion_r110880462","pull_request_url":"https://api.github.com/repos/CSCfi/pebbles/pulls/596","_links":{"self":{"href":"https://api.github.com/repos/CSCfi/pebbles/pulls/comments/110880462"},"html":{"href":"https://github.com/CSCfi/pebbles/pull/596#discussion_r110880462"},"pull_request":{"href":"https://api.github.com/repos/CSCfi/pebbles/pulls/596"}}},"pull_request":{"url":"https://api.github.com/repos/CSCfi/pebbles/pulls/596","id":114815121,"html_url":"https://github.com/CSCfi/pebbles/pull/596","diff_url":"https://github.com/CSCfi/pebbles/pull/596.diff","patch_url":"https://github.com/CSCfi/pebbles/pull/596.patch","issue_url":"https://api.github.com/repos/CSCfi/pebbles/issues/596","number":596,"state":"open","locked":false,"title":"Namespaced Key Value based storage. Closes #595","user":{"login":"apurva3000","id":6124928,"avatar_url":"https://avatars0.githubusercontent.com/u/6124928?v=3","gravatar_id":"","url":"https://api.github.com/users/apurva3000","html_url":"https://github.com/apurva3000","followers_url":"https://api.github.com/users/apurva3000/followers","following_url":"https://api.github.com/users/apurva3000/following{/other_user}","gists_url":"https://api.github.com/users/apurva3000/gists{/gist_id}","starred_url":"https://api.github.com/users/apurva3000/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apurva3000/subscriptions","organizations_url":"https://api.github.com/users/apurva3000/orgs","repos_url":"https://api.github.com/users/apurva3000/repos","events_url":"https://api.github.com/users/apurva3000/events{/privacy}","received_events_url":"https://api.github.com/users/apurva3000/received_events","type":"User","site_admin":false},"body":"Tests added","created_at":"2017-04-07T13:24:14Z","updated_at":"2017-04-11T11:46:13Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1297c9258a1f2e465530d61784b6b9ccb9345301","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/CSCfi/pebbles/pulls/596/commits","review_comments_url":"https://api.github.com/repos/CSCfi/pebbles/pulls/596/comments","review_comment_url":"https://api.github.com/repos/CSCfi/pebbles/pulls/comments{/number}","comments_url":"https://api.github.com/repos/CSCfi/pebbles/issues/596/comments","statuses_url":"https://api.github.com/repos/CSCfi/pebbles/statuses/06ca64f3ab18082c86add51bf3ec9c0f1366853f","head":{"label":"CSCfi:feature/namespaced_key_value_storage#595","ref":"feature/namespaced_key_value_storage#595","sha":"06ca64f3ab18082c86add51bf3ec9c0f1366853f","user":{"login":"CSCfi","id":5947494,"avatar_url":"https://avatars2.githubusercontent.com/u/5947494?v=3","gravatar_id":"","url":"https://api.github.com/users/CSCfi","html_url":"https://github.com/CSCfi","followers_url":"https://api.github.com/users/CSCfi/followers","following_url":"https://api.github.com/users/CSCfi/following{/other_user}","gists_url":"https://api.github.com/users/CSCfi/gists{/gist_id}","starred_url":"https://api.github.com/users/CSCfi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CSCfi/subscriptions","organizations_url":"https://api.github.com/users/CSCfi/orgs","repos_url":"https://api.github.com/users/CSCfi/repos","events_url":"https://api.github.com/users/CSCfi/events{/privacy}","received_events_url":"https://api.github.com/users/CSCfi/received_events","type":"Organization","site_admin":false},"repo":{"id":27765622,"name":"pebbles","full_name":"CSCfi/pebbles","owner":{"login":"CSCfi","id":5947494,"avatar_url":"https://avatars2.githubusercontent.com/u/5947494?v=3","gravatar_id":"","url":"https://api.github.com/users/CSCfi","html_url":"https://github.com/CSCfi","followers_url":"https://api.github.com/users/CSCfi/followers","following_url":"https://api.github.com/users/CSCfi/following{/other_user}","gists_url":"https://api.github.com/users/CSCfi/gists{/gist_id}","starred_url":"https://api.github.com/users/CSCfi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CSCfi/subscriptions","organizations_url":"https://api.github.com/users/CSCfi/orgs","repos_url":"https://api.github.com/users/CSCfi/repos","events_url":"https://api.github.com/users/CSCfi/events{/privacy}","received_events_url":"https://api.github.com/users/CSCfi/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/CSCfi/pebbles","description":"Pebbles is a frontend to manage cloud resources and lightweight user accounts. ","fork":false,"url":"https://api.github.com/repos/CSCfi/pebbles","forks_url":"https://api.github.com/repos/CSCfi/pebbles/forks","keys_url":"https://api.github.com/repos/CSCfi/pebbles/keys{/key_id}","collaborators_url":"https://api.github.com/repos/CSCfi/pebbles/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/CSCfi/pebbles/teams","hooks_url":"https://api.github.com/repos/CSCfi/pebbles/hooks","issue_events_url":"https://api.github.com/repos/CSCfi/pebbles/issues/events{/number}","events_url":"https://api.github.com/repos/CSCfi/pebbles/events","assignees_url":"https://api.github.com/repos/CSCfi/pebbles/assignees{/user}","branches_url":"https://api.github.com/repos/CSCfi/pebbles/branches{/branch}","tags_url":"https://api.github.com/repos/CSCfi/pebbles/tags","blobs_url":"https://api.github.com/repos/CSCfi/pebbles/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/CSCfi/pebbles/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/CSCfi/pebbles/git/refs{/sha}","trees_url":"https://api.github.com/repos/CSCfi/pebbles/git/trees{/sha}","statuses_url":"https://api.github.com/repos/CSCfi/pebbles/statuses/{sha}","languages_url":"https://api.github.com/repos/CSCfi/pebbles/languages","stargazers_url":"https://api.github.com/repos/CSCfi/pebbles/stargazers","contributors_url":"https://api.github.com/repos/CSCfi/pebbles/contributors","subscribers_url":"https://api.github.com/repos/CSCfi/pebbles/subscribers","subscription_url":"https://api.github.com/repos/CSCfi/pebbles/subscription","commits_url":"https://api.github.com/repos/CSCfi/pebbles/commits{/sha}","git_commits_url":"https://api.github.com/repos/CSCfi/pebbles/git/commits{/sha}","comments_url":"https://api.github.com/repos/CSCfi/pebbles/comments{/number}","issue_comment_url":"https://api.github.com/repos/CSCfi/pebbles/issues/comments{/number}","contents_url":"https://api.github.com/repos/CSCfi/pebbles/contents/{+path}","compare_url":"https://api.github.com/repos/CSCfi/pebbles/compare/{base}...{head}","merges_url":"https://api.github.com/repos/CSCfi/pebbles/merges","archive_url":"https://api.github.com/repos/CSCfi/pebbles/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/CSCfi/pebbles/downloads","issues_url":"https://api.github.com/repos/CSCfi/pebbles/issues{/number}","pulls_url":"https://api.github.com/repos/CSCfi/pebbles/pulls{/number}","milestones_url":"https://api.github.com/repos/CSCfi/pebbles/milestones{/number}","notifications_url":"https://api.github.com/repos/CSCfi/pebbles/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/CSCfi/pebbles/labels{/name}","releases_url":"https://api.github.com/repos/CSCfi/pebbles/releases{/id}","deployments_url":"https://api.github.com/repos/CSCfi/pebbles/deployments","created_at":"2014-12-09T12:31:14Z","updated_at":"2017-03-02T14:10:41Z","pushed_at":"2017-04-07T13:24:14Z","git_url":"git://github.com/CSCfi/pebbles.git","ssh_url":"git@github.com:CSCfi/pebbles.git","clone_url":"https://github.com/CSCfi/pebbles.git","svn_url":"https://github.com/CSCfi/pebbles","homepage":"","size":3068,"stargazers_count":4,"watchers_count":4,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":6,"mirror_url":null,"open_issues_count":49,"forks":6,"open_issues":49,"watchers":4,"default_branch":"master"}},"base":{"label":"CSCfi:master","ref":"master","sha":"c6be4cac46b4dc49093b5f63760ec0e2c27894c1","user":{"login":"CSCfi","id":5947494,"avatar_url":"https://avatars2.githubusercontent.com/u/5947494?v=3","gravatar_id":"","url":"https://api.github.com/users/CSCfi","html_url":"https://github.com/CSCfi","followers_url":"https://api.github.com/users/CSCfi/followers","following_url":"https://api.github.com/users/CSCfi/following{/other_user}","gists_url":"https://api.github.com/users/CSCfi/gists{/gist_id}","starred_url":"https://api.github.com/users/CSCfi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CSCfi/subscriptions","organizations_url":"https://api.github.com/users/CSCfi/orgs","repos_url":"https://api.github.com/users/CSCfi/repos","events_url":"https://api.github.com/users/CSCfi/events{/privacy}","received_events_url":"https://api.github.com/users/CSCfi/received_events","type":"Organization","site_admin":false},"repo":{"id":27765622,"name":"pebbles","full_name":"CSCfi/pebbles","owner":{"login":"CSCfi","id":5947494,"avatar_url":"https://avatars2.githubusercontent.com/u/5947494?v=3","gravatar_id":"","url":"https://api.github.com/users/CSCfi","html_url":"https://github.com/CSCfi","followers_url":"https://api.github.com/users/CSCfi/followers","following_url":"https://api.github.com/users/CSCfi/following{/other_user}","gists_url":"https://api.github.com/users/CSCfi/gists{/gist_id}","starred_url":"https://api.github.com/users/CSCfi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CSCfi/subscriptions","organizations_url":"https://api.github.com/users/CSCfi/orgs","repos_url":"https://api.github.com/users/CSCfi/repos","events_url":"https://api.github.com/users/CSCfi/events{/privacy}","received_events_url":"https://api.github.com/users/CSCfi/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/CSCfi/pebbles","description":"Pebbles is a frontend to manage cloud resources and lightweight user accounts. ","fork":false,"url":"https://api.github.com/repos/CSCfi/pebbles","forks_url":"https://api.github.com/repos/CSCfi/pebbles/forks","keys_url":"https://api.github.com/repos/CSCfi/pebbles/keys{/key_id}","collaborators_url":"https://api.github.com/repos/CSCfi/pebbles/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/CSCfi/pebbles/teams","hooks_url":"https://api.github.com/repos/CSCfi/pebbles/hooks","issue_events_url":"https://api.github.com/repos/CSCfi/pebbles/issues/events{/number}","events_url":"https://api.github.com/repos/CSCfi/pebbles/events","assignees_url":"https://api.github.com/repos/CSCfi/pebbles/assignees{/user}","branches_url":"https://api.github.com/repos/CSCfi/pebbles/branches{/branch}","tags_url":"https://api.github.com/repos/CSCfi/pebbles/tags","blobs_url":"https://api.github.com/repos/CSCfi/pebbles/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/CSCfi/pebbles/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/CSCfi/pebbles/git/refs{/sha}","trees_url":"https://api.github.com/repos/CSCfi/pebbles/git/trees{/sha}","statuses_url":"https://api.github.com/repos/CSCfi/pebbles/statuses/{sha}","languages_url":"https://api.github.com/repos/CSCfi/pebbles/languages","stargazers_url":"https://api.github.com/repos/CSCfi/pebbles/stargazers","contributors_url":"https://api.github.com/repos/CSCfi/pebbles/contributors","subscribers_url":"https://api.github.com/repos/CSCfi/pebbles/subscribers","subscription_url":"https://api.github.com/repos/CSCfi/pebbles/subscription","commits_url":"https://api.github.com/repos/CSCfi/pebbles/commits{/sha}","git_commits_url":"https://api.github.com/repos/CSCfi/pebbles/git/commits{/sha}","comments_url":"https://api.github.com/repos/CSCfi/pebbles/comments{/number}","issue_comment_url":"https://api.github.com/repos/CSCfi/pebbles/issues/comments{/number}","contents_url":"https://api.github.com/repos/CSCfi/pebbles/contents/{+path}","compare_url":"https://api.github.com/repos/CSCfi/pebbles/compare/{base}...{head}","merges_url":"https://api.github.com/repos/CSCfi/pebbles/merges","archive_url":"https://api.github.com/repos/CSCfi/pebbles/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/CSCfi/pebbles/downloads","issues_url":"https://api.github.com/repos/CSCfi/pebbles/issues{/number}","pulls_url":"https://api.github.com/repos/CSCfi/pebbles/pulls{/number}","milestones_url":"https://api.github.com/repos/CSCfi/pebbles/milestones{/number}","notifications_url":"https://api.github.com/repos/CSCfi/pebbles/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/CSCfi/pebbles/labels{/name}","releases_url":"https://api.github.com/repos/CSCfi/pebbles/releases{/id}","deployments_url":"https://api.github.com/repos/CSCfi/pebbles/deployments","created_at":"2014-12-09T12:31:14Z","updated_at":"2017-03-02T14:10:41Z","pushed_at":"2017-04-07T13:24:14Z","git_url":"git://github.com/CSCfi/pebbles.git","ssh_url":"git@github.com:CSCfi/pebbles.git","clone_url":"https://github.com/CSCfi/pebbles.git","svn_url":"https://github.com/CSCfi/pebbles","homepage":"","size":3068,"stargazers_count":4,"watchers_count":4,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":6,"mirror_url":null,"open_issues_count":49,"forks":6,"open_issues":49,"watchers":4,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/CSCfi/pebbles/pulls/596"},"html":{"href":"https://github.com/CSCfi/pebbles/pull/596"},"issue":{"href":"https://api.github.com/repos/CSCfi/pebbles/issues/596"},"comments":{"href":"https://api.github.com/repos/CSCfi/pebbles/issues/596/comments"},"review_comments":{"href":"https://api.github.com/repos/CSCfi/pebbles/pulls/596/comments"},"review_comment":{"href":"https://api.github.com/repos/CSCfi/pebbles/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/CSCfi/pebbles/pulls/596/commits"},"statuses":{"href":"https://api.github.com/repos/CSCfi/pebbles/statuses/06ca64f3ab18082c86add51bf3ec9c0f1366853f"}}}}
{"actor":{"display_login":"apurva3000"}}