tests_doc2.py 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # Licensed to Cloudera, Inc. under one
  4. # or more contributor license agreements. See the NOTICE file
  5. # distributed with this work for additional information
  6. # regarding copyright ownership. Cloudera, Inc. licenses this file
  7. # to you under the Apache License, Version 2.0 (the
  8. # "License"); you may not use this file except in compliance
  9. # with the License. You may obtain a copy of the License at
  10. #
  11. # http://www.apache.org/licenses/LICENSE-2.0
  12. #
  13. # Unless required by applicable law or agreed to in writing, software
  14. # distributed under the License is distributed on an "AS IS" BASIS,
  15. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. # See the License for the specific language governing permissions and
  17. # limitations under the License.
  18. import json
  19. from datetime import datetime
  20. from nose.plugins.skip import SkipTest
  21. from nose.tools import assert_equal, assert_false, assert_true, assert_not_equal, assert_raises
  22. from django.contrib.auth.models import User
  23. from django.core import management
  24. from django.db.utils import OperationalError
  25. from desktop.converters import DocumentConverter
  26. from desktop.lib.django_test_util import make_logged_in_client
  27. from desktop.lib.test_utils import grant_access
  28. from desktop.models import Directory, Document2
  29. from notebook.models import import_saved_beeswax_query
  30. from beeswax.models import SavedQuery
  31. from beeswax.design import hql_query
  32. from useradmin.models import get_default_user_group
  33. class TestDocument2(object):
  34. def setUp(self):
  35. self.client = make_logged_in_client(username="doc2", groupname="doc2", recreate=True, is_superuser=False)
  36. self.user = User.objects.get(username="doc2")
  37. grant_access("doc2", "doc2", "beeswax")
  38. # This creates the user directories for the new user
  39. response = self.client.get('/desktop/api2/doc/')
  40. data = json.loads(response.content)
  41. assert_equal('/', data['document']['path'], data)
  42. self.home_dir = Document2.objects.get_home_directory(user=self.user)
  43. def test_trash_directory(self):
  44. assert_true(Directory.objects.filter(owner=self.user, name=Document2.TRASH_DIR, type='directory').exists())
  45. def test_document_create(self):
  46. sql = 'SELECT * FROM sample_07'
  47. design = hql_query(sql)
  48. # is_auto
  49. # is_trashed
  50. # is_redacted
  51. old_query = SavedQuery.objects.create(
  52. type=SavedQuery.TYPES_MAPPING['hql'],
  53. owner=self.user,
  54. data=design.dumps(),
  55. name='See examples',
  56. desc='Example of old format'
  57. )
  58. try:
  59. new_query = import_saved_beeswax_query(old_query)
  60. new_query_data = new_query.get_data()
  61. assert_equal('query-hive', new_query_data['type'])
  62. assert_equal('See examples', new_query_data['name'])
  63. assert_equal('Example of old format', new_query_data['description'])
  64. assert_equal('ready', new_query_data['snippets'][0]['status'])
  65. assert_equal('See examples', new_query_data['snippets'][0]['name'])
  66. assert_equal('SELECT * FROM sample_07', new_query_data['snippets'][0]['statement_raw'])
  67. assert_equal([], new_query_data['snippets'][0]['properties']['settings'])
  68. assert_equal([], new_query_data['snippets'][0]['properties']['files'])
  69. assert_equal([], new_query_data['snippets'][0]['properties']['functions'])
  70. finally:
  71. old_query.delete()
  72. def test_get_document(self):
  73. doc = Document2.objects.create(name='test_doc', type='query-hive', owner=self.user, data={})
  74. self.home_dir.children.add(doc)
  75. response = self.client.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  76. data = json.loads(response.content)
  77. assert_true('document' in data)
  78. assert_equal(doc.uuid, data['document']['uuid'])
  79. # Invalid uuid returns error
  80. response = self.client.get('/desktop/api2/doc/', {'uuid': '1234-5678-9'})
  81. data = json.loads(response.content)
  82. assert_equal(-1, data['status'])
  83. assert_true('not found' in data['message'])
  84. # Document UUID and XML UUID missmatch
  85. response = self.client.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  86. data = json.loads(response.content)
  87. doc.uuid = '1234-5678-9'
  88. doc.save()
  89. assert_not_equal(doc.uuid, data['document']['uuid'])
  90. response = self.client.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  91. data = json.loads(response.content)
  92. assert_equal(doc.uuid, data['document']['uuid'])
  93. def test_directory_create_and_rename(self):
  94. response = self.client.post('/desktop/api2/doc/mkdir', {'parent_uuid': json.dumps(self.home_dir.uuid), 'name': json.dumps('test_mkdir')})
  95. data = json.loads(response.content)
  96. assert_equal(0, data['status'], data)
  97. assert_true('directory' in data)
  98. assert_equal(data['directory']['name'], 'test_mkdir', data)
  99. assert_equal(data['directory']['type'], 'directory', data)
  100. response = self.client.post('/desktop/api2/doc/update', {'uuid': json.dumps(data['directory']['uuid']),
  101. 'name': 'updated'})
  102. data = json.loads(response.content)
  103. assert_equal(0, data['status'])
  104. assert_equal('updated', data['document']['name'], data)
  105. def test_file_move(self):
  106. source_dir = Directory.objects.create(name='test_mv_file_src', owner=self.user, parent_directory=self.home_dir)
  107. target_dir = Directory.objects.create(name='test_mv_file_dst', owner=self.user, parent_directory=self.home_dir)
  108. doc = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={}, parent_directory=source_dir)
  109. orig_last_modified = doc.last_modified
  110. # Verify original paths before move operation
  111. response = self.client.get('/desktop/api2/doc/', {'uuid': source_dir.uuid})
  112. data = json.loads(response.content)
  113. assert_equal('/test_mv_file_src', data['document']['path'])
  114. response = self.client.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  115. data = json.loads(response.content)
  116. assert_equal('/test_mv_file_src/query1.sql', data['document']['path'])
  117. response = self.client.post('/desktop/api2/doc/move', {
  118. 'source_doc_uuid': json.dumps(doc.uuid),
  119. 'destination_doc_uuid': json.dumps(target_dir.uuid)
  120. })
  121. data = json.loads(response.content)
  122. assert_equal(0, data['status'], data)
  123. # Verify that the paths are updated
  124. response = self.client.get('/desktop/api2/doc/', {'uuid': source_dir.uuid})
  125. data = json.loads(response.content)
  126. assert_false(any(doc['uuid'] == doc.uuid for doc in data['children']), data['children'])
  127. response = self.client.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  128. data = json.loads(response.content)
  129. assert_equal('/test_mv_file_dst/query1.sql', data['document']['path'])
  130. # Verify that last_modified is intact
  131. doc = Document2.objects.get(id = doc.id)
  132. assert_equal(orig_last_modified.strftime('%Y-%m-%dT%H:%M:%S'), doc.last_modified.strftime('%Y-%m-%dT%H:%M:%S'))
  133. def test_directory_move(self):
  134. source_dir = Directory.objects.create(name='test_mv', owner=self.user, parent_directory=self.home_dir)
  135. target_dir = Directory.objects.create(name='test_mv_dst', owner=self.user, parent_directory=self.home_dir)
  136. doc = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={}, parent_directory=source_dir)
  137. # Verify original paths before move operation
  138. response = self.client.get('/desktop/api2/doc/', {'uuid': source_dir.uuid})
  139. data = json.loads(response.content)
  140. assert_equal('/test_mv', data['document']['path'])
  141. response = self.client.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  142. data = json.loads(response.content)
  143. assert_equal('/test_mv/query1.sql', data['document']['path'])
  144. response = self.client.post('/desktop/api2/doc/move', {
  145. 'source_doc_uuid': json.dumps(Directory.objects.get(owner=self.user, name='test_mv').uuid),
  146. 'destination_doc_uuid': json.dumps(Directory.objects.get(owner=self.user, name='test_mv_dst').uuid)
  147. })
  148. data = json.loads(response.content)
  149. assert_equal(0, data['status'], data)
  150. # Verify that the paths are updated
  151. response = self.client.get('/desktop/api2/doc/', {'uuid': source_dir.uuid})
  152. data = json.loads(response.content)
  153. assert_equal('/test_mv_dst/test_mv', data['document']['path'])
  154. response = self.client.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  155. data = json.loads(response.content)
  156. assert_equal('/test_mv_dst/test_mv/query1.sql', data['document']['path'])
  157. def test_directory_children(self):
  158. # Creates 2 directories and 2 queries and saves to home directory
  159. dir1 = Directory.objects.create(name='test_dir1', owner=self.user)
  160. dir2 = Directory.objects.create(name='test_dir2', owner=self.user)
  161. query1 = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={}, search='foobar')
  162. query2 = Document2.objects.create(name='query2.sql', type='query-hive', owner=self.user, data={}, search='barfoo')
  163. children = [dir1, dir2, query1, query2]
  164. self.home_dir.children.add(*children)
  165. # Test that all children directories and documents are returned
  166. response = self.client.get('/desktop/api2/doc', {'path': '/'})
  167. data = json.loads(response.content)
  168. assert_true('children' in data)
  169. assert_equal(5, data['count']) # This includes the 4 docs and .Trash
  170. # Test filter type
  171. response = self.client.get('/desktop/api2/doc', {'path': '/', 'type': ['directory']})
  172. data = json.loads(response.content)
  173. assert_equal(['directory'], data['types'])
  174. assert_equal(3, data['count'])
  175. assert_true(all(doc['type'] == 'directory' for doc in data['children']))
  176. # Test search text
  177. response = self.client.get('/desktop/api2/doc', {'path': '/', 'text': 'foo'})
  178. data = json.loads(response.content)
  179. assert_equal('foo', data['text'])
  180. assert_equal(2, data['count'])
  181. response = self.client.get('/desktop/api2/doc', {'path': '/', 'text': 'foobar'})
  182. data = json.loads(response.content)
  183. assert_equal(1, data['count'])
  184. # Test pagination with limit
  185. response = self.client.get('/desktop/api2/doc', {'path': '/', 'page': 2, 'limit': 2})
  186. data = json.loads(response.content)
  187. assert_equal(5, data['count'])
  188. assert_equal(2, len(data['children']))
  189. def test_update_document(self):
  190. doc = Document2.objects.create(
  191. name='initial',
  192. description='initial desc',
  193. type='query-hive',
  194. owner=self.user,
  195. data={},
  196. parent_directory=self.home_dir
  197. )
  198. response = self.client.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  199. data = json.loads(response.content)
  200. assert_equal('initial', data['document']['name'])
  201. assert_equal('initial desc', data['document']['description'])
  202. assert_equal('query-hive', data['document']['type'])
  203. # Update document's name and description
  204. response = self.client.post('/desktop/api2/doc/update', {'uuid': json.dumps(doc.uuid),
  205. 'name': 'updated',
  206. 'description': 'updated desc',
  207. 'type': 'bogus-type'})
  208. data = json.loads(response.content)
  209. assert_equal(0, data['status'])
  210. assert_true('document' in data, data)
  211. assert_equal('updated', data['document']['name'], data)
  212. assert_equal('updated desc', data['document']['description'], data)
  213. # Non-whitelisted attributes should remain unchanged
  214. assert_equal('query-hive', data['document']['type'], data)
  215. def test_document_trash(self):
  216. # Create document under home and directory under home with child document
  217. # /
  218. # test_dir/
  219. # query1.sql
  220. # query2.sql
  221. dir = Directory.objects.create(name='test_dir', owner=self.user, parent_directory=self.home_dir)
  222. nested_query = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={}, parent_directory=dir)
  223. query = Document2.objects.create(name='query2.sql', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  224. # Test that .Trash is currently empty
  225. response = self.client.get('/desktop/api2/doc', {'path': '/.Trash'})
  226. data = json.loads(response.content)
  227. assert_equal(0, data['count'])
  228. # Delete query2.sql
  229. assert_false(Document2.objects.get(uuid=query.uuid).is_trashed)
  230. response = self.client.post('/desktop/api2/doc/delete', {'uuid': json.dumps(query.uuid)})
  231. data = json.loads(response.content)
  232. assert_equal(0, data['status'])
  233. assert_true(Document2.objects.get(uuid=query.uuid).is_trashed)
  234. response = self.client.get('/desktop/api2/doc', {'path': '/.Trash'})
  235. data = json.loads(response.content)
  236. assert_equal(1, data['count'])
  237. assert_equal(data['children'][0]['uuid'], query.uuid)
  238. # Delete test_dir directory w/ contents
  239. assert_false(Document2.objects.get(uuid=dir.uuid).is_trashed)
  240. response = self.client.post('/desktop/api2/doc/delete', {'uuid': json.dumps(dir.uuid)})
  241. data = json.loads(response.content)
  242. assert_equal(0, data['status'], data)
  243. assert_true(Document2.objects.get(uuid=dir.uuid).is_trashed)
  244. response = self.client.get('/desktop/api2/doc', {'path': '/.Trash'})
  245. data = json.loads(response.content)
  246. assert_equal(2, data['count'])
  247. # Child document should be in trash too
  248. response = self.client.get('/desktop/api2/doc', {'path': '/.Trash/test_dir'})
  249. data = json.loads(response.content)
  250. assert_equal(nested_query.uuid, data['children'][0]['uuid'])
  251. # Skip Trash (erase) on a directory with contents should erase all children recursively
  252. response = self.client.post('/desktop/api2/doc/delete', {'uuid': json.dumps(dir.uuid), 'skip_trash': json.dumps(True)})
  253. data = json.loads(response.content)
  254. assert_equal(0, data['status'])
  255. assert_false(Document2.objects.filter(uuid=dir.uuid).exists())
  256. assert_false(Document2.objects.filter(uuid=nested_query.uuid).exists())
  257. # Verify that only doc in home is .Trash
  258. response = self.client.get('/desktop/api2/doc', {'path': '/'})
  259. data = json.loads(response.content)
  260. assert_true('children' in data)
  261. assert_equal(1, data['count'])
  262. assert_equal(Document2.TRASH_DIR, data['children'][0]['name'])
  263. def test_validate_immutable_user_directories(self):
  264. # Test that home and Trash directories cannot be recreated or modified
  265. test_dir = Directory.objects.create(name='test_dir', owner=self.user, parent_directory=self.home_dir)
  266. response = self.client.post('/desktop/api2/doc/mkdir', {'parent_uuid': json.dumps(test_dir.uuid), 'name': json.dumps(Document2.TRASH_DIR)})
  267. data = json.loads(response.content)
  268. assert_equal(-1, data['status'], data)
  269. assert_equal('Cannot create or modify directory with name: .Trash', data['message'])
  270. response = self.client.post('/desktop/api2/doc/move', {
  271. 'source_doc_uuid': json.dumps(self.home_dir.uuid),
  272. 'destination_doc_uuid': json.dumps(test_dir.uuid)
  273. })
  274. data = json.loads(response.content)
  275. assert_equal(-1, data['status'], data)
  276. assert_equal('Cannot create or modify directory with name: ', data['message'])
  277. trash_dir = Directory.objects.get(name=Document2.TRASH_DIR, owner=self.user)
  278. response = self.client.post('/desktop/api2/doc/move', {
  279. 'source_doc_uuid': json.dumps(trash_dir.uuid),
  280. 'destination_doc_uuid': json.dumps(test_dir.uuid)
  281. })
  282. data = json.loads(response.content)
  283. assert_equal(-1, data['status'], data)
  284. assert_equal('Cannot create or modify directory with name: .Trash', data['message'])
  285. def test_validate_circular_directory(self):
  286. # Test that saving a document with cycle raises an error, i.e. - This should fail:
  287. # a.parent_directory = b
  288. # b.parent_directory = c
  289. # c.parent_directory = a
  290. c_dir = Directory.objects.create(name='c', owner=self.user)
  291. b_dir = Directory.objects.create(name='b', owner=self.user, parent_directory=c_dir)
  292. a_dir = Directory.objects.create(name='a', owner=self.user, parent_directory=b_dir)
  293. response = self.client.post('/desktop/api2/doc/move', {
  294. 'source_doc_uuid': json.dumps(c_dir.uuid),
  295. 'destination_doc_uuid': json.dumps(a_dir.uuid)
  296. })
  297. data = json.loads(response.content)
  298. assert_equal(-1, data['status'], data)
  299. assert_true('circular dependency' in data['message'], data)
  300. # Test simple case where directory is saved to self as parent
  301. dir = Directory.objects.create(name='dir', owner=self.user)
  302. response = self.client.post('/desktop/api2/doc/move', {
  303. 'source_doc_uuid': json.dumps(dir.uuid),
  304. 'destination_doc_uuid': json.dumps(dir.uuid)
  305. })
  306. data = json.loads(response.content)
  307. assert_equal(-1, data['status'], data)
  308. assert_true('circular dependency' in data['message'], data)
  309. def test_api_get_data(self):
  310. doc_data = {'info': 'hello', 'is_history': False}
  311. doc = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data=json.dumps(doc_data))
  312. doc_data.update({'id': doc.id, 'uuid': doc.uuid})
  313. response = self.client.get('/desktop/api2/doc/', {
  314. 'uuid': doc.uuid,
  315. })
  316. data = json.loads(response.content)
  317. assert_true('document' in data, data)
  318. assert_false(data['data'], data)
  319. response = self.client.get('/desktop/api2/doc/', {
  320. 'uuid': doc.uuid,
  321. 'data': 'true'
  322. })
  323. data = json.loads(response.content)
  324. assert_true('data' in data, data)
  325. assert_equal(data['data'], doc_data)
  326. def test_is_trashed_migration(self):
  327. # Skipping to prevent failing tests in TestOozieSubmissions
  328. raise SkipTest
  329. start_migration = '0024_auto__add_field_document2_is_managed'
  330. mid_migration = '0025_auto__add_field_document2_is_trashed'
  331. end_migration = '0026_change_is_trashed_default_to_false'
  332. APP = 'desktop'
  333. # Making sure Migration is up-to-date with fake migrations
  334. management.call_command('migrate', 'desktop', fake=True, verbosity=0)
  335. dir = Directory.objects.create(name='test_dir', owner=self.user, parent_directory=self.home_dir)
  336. query = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={}, parent_directory=dir)
  337. trashed_query = Document2.objects.create(name='query2.sql', type='query-hive', owner=self.user, data={}, parent_directory=dir)
  338. trashed_query.trash()
  339. try:
  340. assert_false(dir.is_trashed)
  341. assert_false(query.is_trashed)
  342. assert_true(trashed_query.is_trashed)
  343. # Reverse migrate to 0025
  344. management.call_command('migrate', APP, mid_migration, verbosity=0)
  345. dir = Document2.objects.get(uuid=dir.uuid)
  346. query = Document2.objects.get(uuid=query.uuid)
  347. trashed_query = Document2.objects.get(uuid=trashed_query.uuid)
  348. assert_false(dir.is_trashed)
  349. assert_false(query.is_trashed)
  350. assert_true(trashed_query.is_trashed)
  351. # Reverse migrate to 0024. Deletes 'is_trashed' field from desktop_documents2
  352. management.call_command('migrate', APP, start_migration, verbosity=0)
  353. assert_raises(OperationalError, Document2.objects.get, uuid=dir.uuid)
  354. assert_raises(OperationalError, Document2.objects.get, uuid=query.uuid)
  355. assert_raises(OperationalError, Document2.objects.get, uuid=trashed_query.uuid)
  356. # Forward migrate to 0025
  357. management.call_command('migrate', APP, mid_migration, verbosity=0)
  358. dir = Document2.objects.get(uuid=dir.uuid)
  359. query = Document2.objects.get(uuid=query.uuid)
  360. trashed_query = Document2.objects.get(uuid=trashed_query.uuid)
  361. assert_true(dir.is_trashed is None)
  362. assert_true(query.is_trashed is None)
  363. assert_true(trashed_query.is_trashed is None)
  364. # Forward migrate to 0026
  365. management.call_command('migrate', APP, end_migration, verbosity=0)
  366. dir = Document2.objects.get(uuid=dir.uuid)
  367. query = Document2.objects.get(uuid=query.uuid)
  368. trashed_query = Document2.objects.get(uuid=trashed_query.uuid)
  369. assert_true(dir.is_trashed is None)
  370. assert_true(query.is_trashed is None)
  371. assert_true(trashed_query.is_trashed is None)
  372. # New Documents should have is_trashed=False
  373. query1 = Document2.objects.create(name='new_query.sql', type='query-hive', owner=self.user, data={}, parent_directory=dir)
  374. assert_true(query1.is_trashed is False)
  375. # Create history doc
  376. query1.is_history = True
  377. query1.save()
  378. query1 = Document2.objects.get(uuid=query1.uuid)
  379. query1_last_modified = query1.last_modified
  380. dir_last_modified = dir.last_modified
  381. query_last_modified = query.last_modified
  382. trashed_query_last_modified = trashed_query.last_modified
  383. # Converter sets is_trashed=True for currently trashed docs
  384. converter = DocumentConverter(self.user)
  385. converter.convert()
  386. trashed_query = Document2.objects.get(uuid=trashed_query.uuid)
  387. dir = Document2.objects.get(uuid=dir.uuid)
  388. query = Document2.objects.get(uuid=query.uuid)
  389. assert_true(trashed_query.is_trashed)
  390. assert_true(dir.is_trashed is False)
  391. assert_true(query.is_trashed is False)
  392. # last_modified should be retained post conversion
  393. assert_equal(dir_last_modified, dir.last_modified)
  394. assert_equal(query_last_modified, query.last_modified)
  395. assert_equal(trashed_query_last_modified, trashed_query.last_modified)
  396. query1 = Document2.objects.get(uuid=query1.uuid)
  397. assert_equal(query1_last_modified, query1.last_modified)
  398. finally:
  399. # Delete docs
  400. dir.delete()
  401. query.delete()
  402. query1.delete()
  403. trashed_query.delete()
  404. class TestDocument2Permissions(object):
  405. def setUp(self):
  406. self.client = make_logged_in_client(username="perm_user", groupname="default", recreate=True, is_superuser=False)
  407. self.client_not_me = make_logged_in_client(username="not_perm_user", groupname="default", recreate=True, is_superuser=False)
  408. self.user = User.objects.get(username="perm_user")
  409. self.user_not_me = User.objects.get(username="not_perm_user")
  410. grant_access(self.user.username, self.user.username, "desktop")
  411. grant_access(self.user_not_me.username, self.user_not_me.username, "desktop")
  412. self.default_group = get_default_user_group()
  413. # This creates the user directories for the new user
  414. response = self.client.get('/desktop/api2/doc/')
  415. data = json.loads(response.content)
  416. assert_equal('/', data['document']['path'], data)
  417. self.home_dir = Document2.objects.get_home_directory(user=self.user)
  418. def test_default_permissions(self):
  419. # Tests that for a new doc by default, read/write perms are set to no users and no groups
  420. new_doc = Document2.objects.create(name='new_doc', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  421. response = self.client.get('/desktop/api2/doc/', {'uuid': new_doc.uuid})
  422. data = json.loads(response.content)
  423. assert_equal(new_doc.uuid, data['document']['uuid'], data)
  424. assert_true('perms' in data['document'])
  425. assert_equal({'read': {'users': [], 'groups': []}, 'write': {'users': [], 'groups': []}},
  426. data['document']['perms'])
  427. def test_share_document_read_by_user(self):
  428. doc = Document2.objects.create(name='new_doc', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  429. # owner can view document
  430. response = self.client.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  431. data = json.loads(response.content)
  432. assert_equal(doc.uuid, data['document']['uuid'], data)
  433. # other user cannot view document
  434. response = self.client_not_me.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  435. data = json.loads(response.content)
  436. assert_equal(-1, data['status'])
  437. # Share read perm by users
  438. response = self.client.post("/desktop/api2/doc/share", {
  439. 'uuid': json.dumps(doc.uuid),
  440. 'data': json.dumps({
  441. 'read': {
  442. 'user_ids': [
  443. self.user.id,
  444. self.user_not_me.id
  445. ],
  446. 'group_ids': [],
  447. },
  448. 'write': {
  449. 'user_ids': [],
  450. 'group_ids': [],
  451. }
  452. })
  453. })
  454. assert_equal(0, json.loads(response.content)['status'], response.content)
  455. assert_true(doc.can_read(self.user))
  456. assert_true(doc.can_write(self.user))
  457. assert_true(doc.can_read(self.user_not_me))
  458. assert_false(doc.can_write(self.user_not_me))
  459. # other user can view document
  460. response = self.client_not_me.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  461. data = json.loads(response.content)
  462. assert_equal(doc.uuid, data['document']['uuid'], data)
  463. # other user can share document with read permissions
  464. response = self.client_not_me.post("/desktop/api2/doc/share", {
  465. 'uuid': json.dumps(doc.uuid),
  466. 'data': json.dumps({
  467. 'read': {
  468. 'user_ids': [],
  469. 'group_ids': [
  470. self.default_group.id
  471. ],
  472. },
  473. 'write': {
  474. 'user_ids': [],
  475. 'group_ids': [],
  476. }
  477. })
  478. })
  479. assert_equal(0, json.loads(response.content)['status'], response.content)
  480. # other user cannot share document with write permissions
  481. response = self.client_not_me.post("/desktop/api2/doc/share", {
  482. 'uuid': json.dumps(doc.uuid),
  483. 'data': json.dumps({
  484. 'read': {
  485. 'user_ids': [],
  486. 'group_ids': [],
  487. },
  488. 'write': {
  489. 'user_ids': [],
  490. 'group_ids': [
  491. self.default_group.id
  492. ],
  493. }
  494. })
  495. })
  496. assert_equal(-1, json.loads(response.content)['status'], response.content)
  497. def test_share_document_read_by_group(self):
  498. doc = Document2.objects.create(name='new_doc', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  499. # owner can view document
  500. response = self.client.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  501. data = json.loads(response.content)
  502. assert_equal(doc.uuid, data['document']['uuid'], data)
  503. # other user cannot view document
  504. response = self.client_not_me.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  505. data = json.loads(response.content)
  506. assert_equal(-1, data['status'])
  507. response = self.client.post("/desktop/api2/doc/share", {
  508. 'uuid': json.dumps(doc.uuid),
  509. 'data': json.dumps({
  510. 'read': {
  511. 'user_ids': [
  512. self.user.id
  513. ],
  514. 'group_ids': [
  515. self.default_group.id
  516. ]
  517. },
  518. 'write': {
  519. 'user_ids': [],
  520. 'group_ids': []
  521. }
  522. })
  523. })
  524. assert_equal(0, json.loads(response.content)['status'], response.content)
  525. assert_true(doc.can_read(self.user))
  526. assert_true(doc.can_write(self.user))
  527. assert_true(doc.can_read(self.user_not_me))
  528. assert_false(doc.can_write(self.user_not_me))
  529. # other user can view document
  530. response = self.client_not_me.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  531. data = json.loads(response.content)
  532. assert_equal(doc.uuid, data['document']['uuid'], data)
  533. def test_share_document_write_by_user(self):
  534. doc = Document2.objects.create(name='new_doc', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  535. # other user cannot modify document
  536. response = self.client_not_me.post('/desktop/api2/doc/delete', {'uuid': json.dumps(doc.uuid)})
  537. data = json.loads(response.content)
  538. assert_equal(-1, data['status'])
  539. # Share write perm by user
  540. response = self.client.post("/desktop/api2/doc/share", {
  541. 'uuid': json.dumps(doc.uuid),
  542. 'data': json.dumps({
  543. 'read': {
  544. 'user_ids': [
  545. self.user.id
  546. ],
  547. 'group_ids': []
  548. },
  549. 'write': {
  550. 'user_ids': [
  551. self.user_not_me.id
  552. ],
  553. 'group_ids': []
  554. }
  555. })
  556. })
  557. assert_equal(0, json.loads(response.content)['status'], response.content)
  558. assert_true(doc.can_read(self.user))
  559. assert_true(doc.can_write(self.user))
  560. assert_true(doc.can_read(self.user_not_me))
  561. assert_true(doc.can_write(self.user_not_me))
  562. # other user can modify document
  563. response = self.client_not_me.post('/desktop/api2/doc/delete', {'uuid': json.dumps(doc.uuid)})
  564. data = json.loads(response.content)
  565. assert_equal(0, data['status'])
  566. def test_share_document_write_by_group(self):
  567. doc = Document2.objects.create(name='new_doc', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  568. # other user cannot modify document
  569. response = self.client_not_me.post('/desktop/api2/doc/delete', {'uuid': json.dumps(doc.uuid)})
  570. data = json.loads(response.content)
  571. assert_equal(-1, data['status'])
  572. # Share write perm by group
  573. response = self.client.post("/desktop/api2/doc/share", {
  574. 'uuid': json.dumps(doc.uuid),
  575. 'data': json.dumps({
  576. 'read': {
  577. 'user_ids': [
  578. self.user.id
  579. ],
  580. 'group_ids': []
  581. },
  582. 'write': {
  583. 'user_ids': [],
  584. 'group_ids': [
  585. self.default_group.id
  586. ]
  587. }
  588. })
  589. })
  590. assert_equal(0, json.loads(response.content)['status'], response.content)
  591. assert_true(doc.can_read(self.user))
  592. assert_true(doc.can_write(self.user))
  593. assert_true(doc.can_read(self.user_not_me))
  594. assert_true(doc.can_write(self.user_not_me))
  595. # other user can modify document
  596. response = self.client_not_me.post('/desktop/api2/doc/delete', {'uuid': json.dumps(doc.uuid)})
  597. data = json.loads(response.content)
  598. assert_equal(0, data['status'])
  599. def test_share_directory(self):
  600. # Test that updating the permissions for a directory updates all nested documents accordingly, with file structure:
  601. # /
  602. # test_dir/
  603. # query1.sql
  604. # nested_dir/
  605. # query2.sql
  606. # All initially owned by self.user
  607. parent_dir = Directory.objects.create(name='test_dir', owner=self.user, parent_directory=self.home_dir)
  608. child_doc = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={}, parent_directory=parent_dir)
  609. nested_dir = Directory.objects.create(name='nested_dir', owner=self.user, parent_directory=parent_dir)
  610. nested_doc = Document2.objects.create(name='query2.sql', type='query-hive', owner=self.user, data={}, parent_directory=nested_dir)
  611. for doc in [parent_dir, child_doc, nested_dir, nested_doc]:
  612. assert_true(doc.can_read(self.user))
  613. assert_true(doc.can_write(self.user))
  614. assert_false(doc.can_read(self.user_not_me))
  615. assert_false(doc.can_write(self.user_not_me))
  616. # Update parent_dir permissions to grant write permissions to default group
  617. response = self.client.post("/desktop/api2/doc/share", {
  618. 'uuid': json.dumps(parent_dir.uuid),
  619. 'data': json.dumps({
  620. 'read': {
  621. 'user_ids': [],
  622. 'group_ids': []
  623. },
  624. 'write': {
  625. 'user_ids': [],
  626. 'group_ids': [
  627. self.default_group.id
  628. ]
  629. }
  630. })
  631. })
  632. assert_equal(0, json.loads(response.content)['status'], response.content)
  633. for doc in [parent_dir, child_doc, nested_dir, nested_doc]:
  634. assert_true(doc.can_read(self.user))
  635. assert_true(doc.can_write(self.user))
  636. assert_true(doc.can_read(self.user_not_me))
  637. assert_true(doc.can_write(self.user_not_me))
  638. def test_get_shared_documents(self):
  639. not_shared = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  640. shared_1 = Document2.objects.create(name='query2.sql', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  641. shared_2 = Document2.objects.create(name='query3.sql', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  642. shared_1.share(user=self.user, name='read', users=[self.user_not_me], groups=[])
  643. shared_2.share(user=self.user, name='read', users=[self.user_not_me], groups=[])
  644. # 2 shared docs should appear in the other user's shared documents response
  645. response = self.client_not_me.get('/desktop/api2/docs/', {'perms': 'shared'})
  646. data = json.loads(response.content)
  647. assert_true('documents' in data)
  648. assert_equal(2, data['count'])
  649. doc_names = [doc['name'] for doc in data['documents']]
  650. assert_true('query2.sql' in doc_names)
  651. assert_true('query3.sql' in doc_names)
  652. assert_false('query1.sql' in doc_names)
  653. # they should also appear in user's home directory get_documents response
  654. response = self.client_not_me.get('/desktop/api2/doc/')
  655. data = json.loads(response.content)
  656. doc_names = [doc['name'] for doc in data['children']]
  657. assert_true('query2.sql' in doc_names)
  658. assert_true('query3.sql' in doc_names)
  659. def test_get_shared_directories(self):
  660. # Tests that when fetching the shared documents for a user, they are grouped by top-level directory when possible
  661. # /
  662. # dir1/
  663. # query1.sql
  664. # dir2/
  665. # dir3/
  666. # query2.sql
  667. # query3.sql
  668. dir1 = Directory.objects.create(name='dir1', owner=self.user, parent_directory=self.home_dir)
  669. doc1 = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={}, parent_directory=dir1)
  670. dir2 = Directory.objects.create(name='dir2', owner=self.user, parent_directory=self.home_dir)
  671. dir3 = Directory.objects.create(name='dir3', owner=self.user, parent_directory=dir2)
  672. doc2 = Document2.objects.create(name='query2.sql', type='query-hive', owner=self.user, data={}, parent_directory=dir3)
  673. doc3 = Document2.objects.create(name='query3.sql', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  674. dir1.share(user=self.user, name='read', users=[], groups=[self.default_group])
  675. dir3.share(user=self.user, name='read', users=[], groups=[self.default_group])
  676. doc3.share(user=self.user, name='read', users=[], groups=[self.default_group])
  677. # 3 shared docs should appear, due to directory rollup
  678. response = self.client_not_me.get('/desktop/api2/docs/', {'perms': 'shared', 'flatten': 'false'})
  679. data = json.loads(response.content)
  680. assert_true('documents' in data)
  681. assert_equal(3, data['count'], data)
  682. doc_names = [doc['name'] for doc in data['documents']]
  683. assert_true('dir1' in doc_names)
  684. assert_true('dir3' in doc_names)
  685. assert_true('query3.sql' in doc_names)
  686. assert_false('dir2' in doc_names)
  687. # nested documents should not appear
  688. assert_false('query1.sql' in doc_names)
  689. assert_false('query2.sql' in doc_names)
  690. # but nested documents should still be shared/viewable by group
  691. response = self.client_not_me.get('/desktop/api2/doc/', {'uuid': doc1.uuid})
  692. data = json.loads(response.content)
  693. assert_equal(doc1.uuid, data['document']['uuid'], data)
  694. response = self.client_not_me.get('/desktop/api2/doc/', {'uuid': doc2.uuid})
  695. data = json.loads(response.content)
  696. assert_equal(doc2.uuid, data['document']['uuid'], data)
  697. def test_inherit_parent_permissions(self):
  698. # Tests that when saving a document to a shared directory, the doc/dir inherits same permissions
  699. dir1 = Directory.objects.create(name='dir1', owner=self.user, parent_directory=self.home_dir)
  700. dir1.share(user=self.user, name='read', users=[], groups=[self.default_group])
  701. dir1.share(user=self.user, name='write', users=[self.user_not_me], groups=[])
  702. doc1 = Document2.objects.create(name='doc1', owner=self.user, parent_directory=dir1)
  703. response = self.client.get('/desktop/api2/doc/', {'uuid': doc1.uuid})
  704. data = json.loads(response.content)
  705. assert_equal([{'id': self.default_group.id, 'name': self.default_group.name}],
  706. data['document']['perms']['read']['groups'], data)
  707. assert_equal([{'id': self.user_not_me.id, 'username': self.user_not_me.username}],
  708. data['document']['perms']['write']['users'], data)
  709. def test_search_documents(self):
  710. owned_dir = Directory.objects.create(name='test_dir', owner=self.user, parent_directory=self.home_dir)
  711. owned_query = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={}, parent_directory=owned_dir)
  712. owned_history = Document2.objects.create(name='history.sql', type='query-hive', owner=self.user, data={}, is_history=True, parent_directory=owned_dir)
  713. owned_workflow = Document2.objects.create(name='test.wf', type='oozie-workflow2', owner=self.user, data={}, parent_directory=owned_dir)
  714. other_home_dir = Document2.objects.get_home_directory(user=self.user_not_me)
  715. not_shared = Document2.objects.create(name='other_query1.sql', type='query-hive', owner=self.user_not_me, data={}, parent_directory=other_home_dir)
  716. shared_1 = Document2.objects.create(name='other_query2.sql', type='query-hive', owner=self.user_not_me, data={}, parent_directory=other_home_dir)
  717. shared_2 = Document2.objects.create(name='other_query3.sql', type='query-hive', owner=self.user_not_me, data={}, parent_directory=other_home_dir)
  718. shared_1.share(user=self.user_not_me, name='read', users=[self.user], groups=[])
  719. shared_2.share(user=self.user_not_me, name='read', users=[], groups=[self.default_group])
  720. # 3 total docs (1 owned, 2 shared)
  721. response = self.client.get('/desktop/api2/docs/', {'type': 'query-hive'})
  722. data = json.loads(response.content)
  723. assert_true('documents' in data)
  724. assert_equal(3, data['count'])
  725. doc_names = [doc['name'] for doc in data['documents']]
  726. assert_true('query1.sql' in doc_names)
  727. assert_true('other_query2.sql' in doc_names)
  728. assert_true('other_query3.sql' in doc_names)
  729. # Return history docs
  730. response = self.client.get('/desktop/api2/docs/', {'type': 'query-hive', 'include_history': 'true'})
  731. data = json.loads(response.content)
  732. assert_true('documents' in data)
  733. assert_equal(4, data['count'])
  734. doc_names = [doc['name'] for doc in data['documents']]
  735. assert_true('history.sql' in doc_names)
  736. def test_unicode_name(self):
  737. doc = Document2.objects.create(name='My Bundle a voté « non » à l’accord', type='oozie-workflow2', owner=self.user,
  738. data={}, parent_directory=self.home_dir)
  739. # Verify that home directory contents return correctly
  740. response = self.client.get('/desktop/api2/doc/', {'uuid': self.home_dir.uuid})
  741. data = json.loads(response.content)
  742. assert_equal(0, data['status'])
  743. # Verify that the doc's path is escaped
  744. response = self.client.get('/desktop/api2/doc/', {'uuid': doc.uuid})
  745. data = json.loads(response.content)
  746. assert_equal(0, data['status'])
  747. path = data['document']['path']
  748. assert_equal('/My%20Bundle%20a%20vot%C3%A9%20%C2%AB%20non%20%C2%BB%20%C3%A0%20l%E2%80%99accord', path)
  749. class TestDocument2ImportExport(object):
  750. def setUp(self):
  751. self.client = make_logged_in_client(username="perm_user", groupname="default", recreate=True, is_superuser=False)
  752. self.client_not_me = make_logged_in_client(username="not_perm_user", groupname="default", recreate=True, is_superuser=False)
  753. self.user = User.objects.get(username="perm_user")
  754. self.user_not_me = User.objects.get(username="not_perm_user")
  755. grant_access(self.user.username, self.user.username, "desktop")
  756. grant_access(self.user_not_me.username, self.user_not_me.username, "desktop")
  757. self.default_group = get_default_user_group()
  758. # This creates the user directories for the new user
  759. response = self.client.get('/desktop/api2/doc/')
  760. data = json.loads(response.content)
  761. assert_equal('/', data['document']['path'], data)
  762. self.home_dir = Document2.objects.get_home_directory(user=self.user)
  763. self.not_me_home_dir = Document2.objects.get_home_directory(user=self.user_not_me)
  764. def test_export_documents_with_dependencies(self):
  765. query1 = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  766. query2 = Document2.objects.create(name='query2.sql', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  767. query3 = Document2.objects.create(name='query3.sql', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir, is_history=True)
  768. workflow = Document2.objects.create(name='test.wf', type='oozie-workflow2', owner=self.user, data={}, parent_directory=self.home_dir)
  769. workflow.dependencies.add(query1)
  770. workflow.dependencies.add(query2)
  771. workflow.dependencies.add(query3)
  772. # Test that exporting workflow should export all dependencies except history
  773. response = self.client.get('/desktop/api2/doc/export/', {'documents': json.dumps([workflow.id]), 'format': 'json'})
  774. documents = json.loads(response.content)
  775. documents = json.loads(documents)
  776. assert_equal(3, len(documents))
  777. assert_true('test.wf' in [doc['fields']['name'] for doc in documents])
  778. assert_true('query1.sql' in [doc['fields']['name'] for doc in documents])
  779. assert_true('query2.sql' in [doc['fields']['name'] for doc in documents])
  780. assert_false('query3.sql' in [doc['fields']['name'] for doc in documents])
  781. # Test that exporting multiple workflows with overlapping dependencies works
  782. workflow2 = Document2.objects.create(name='test2.wf', type='oozie-workflow2', owner=self.user, data={}, parent_directory=self.home_dir)
  783. workflow2.dependencies.add(query1)
  784. response = self.client.get('/desktop/api2/doc/export/', {'documents': json.dumps([workflow.id, workflow2.id]), 'format': 'json'})
  785. documents = json.loads(response.content)
  786. documents = json.loads(documents)
  787. assert_equal(4, len(documents))
  788. assert_true('test.wf' in [doc['fields']['name'] for doc in documents])
  789. assert_true('test2.wf' in [doc['fields']['name'] for doc in documents])
  790. assert_true('query1.sql' in [doc['fields']['name'] for doc in documents])
  791. assert_true('query2.sql' in [doc['fields']['name'] for doc in documents])
  792. def test_export_documents_file_name(self):
  793. query1 = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={},
  794. parent_directory=self.home_dir)
  795. query2 = Document2.objects.create(name='query2.sql', type='query-hive', owner=self.user, data={},
  796. parent_directory=self.home_dir)
  797. query3 = Document2.objects.create(name='query3.sql', type='query-hive', owner=self.user, data={},
  798. parent_directory=self.home_dir, is_history=True)
  799. workflow = Document2.objects.create(name='test.wf', type='oozie-workflow2', owner=self.user, data={},
  800. parent_directory=self.home_dir)
  801. workflow.dependencies.add(query1)
  802. workflow.dependencies.add(query2)
  803. workflow.dependencies.add(query3)
  804. # Test that exporting multiple workflows with overlapping dependencies works
  805. workflow2 = Document2.objects.create(name='test2.wf', type='oozie-workflow2', owner=self.user, data={},
  806. parent_directory=self.home_dir)
  807. workflow2.dependencies.add(query1)
  808. # Test that exporting to a file includes the date and number of documents in the filename
  809. response = self.client.get('/desktop/api2/doc/export/', {'documents': json.dumps([workflow.id, workflow2.id])})
  810. assert_equal(response['Content-Disposition'], 'attachment; filename=hue-documents-%s-(4).json' % datetime.today().strftime('%Y-%m-%d'))
  811. # Test that exporting single file gets the name of the document in the filename
  812. response = self.client.get('/desktop/api2/doc/export/', {'documents': json.dumps([workflow.id])})
  813. assert_equal(response['Content-Disposition'], 'attachment; filename=' + workflow.name + '.json')
  814. def test_export_directories_with_children(self):
  815. # Test that exporting a directory exports children docs
  816. # /
  817. # dir1/
  818. # query1.sql
  819. # dir2/
  820. # dir3/
  821. # query2.sql
  822. # query3.sql
  823. dir1 = Directory.objects.create(name='dir1', owner=self.user, parent_directory=self.home_dir)
  824. doc1 = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={}, parent_directory=dir1)
  825. dir2 = Directory.objects.create(name='dir2', owner=self.user, parent_directory=self.home_dir)
  826. dir3 = Directory.objects.create(name='dir3', owner=self.user, parent_directory=dir2)
  827. doc2 = Document2.objects.create(name='query2.sql', type='query-hive', owner=self.user, data={}, parent_directory=dir3)
  828. doc3 = Document2.objects.create(name='query3.sql', type='query-hive', owner=self.user, data={}, parent_directory=self.home_dir)
  829. response = self.client.get('/desktop/api2/doc/export/', {'documents': json.dumps([dir1.id, dir2.id, doc3.id]), 'format': 'json'})
  830. documents = json.loads(response.content)
  831. documents = json.loads(documents)
  832. assert_equal(6, len(documents))
  833. assert_true('dir1' in [doc['fields']['name'] for doc in documents])
  834. assert_true('query1.sql' in [doc['fields']['name'] for doc in documents])
  835. assert_true('dir2' in [doc['fields']['name'] for doc in documents])
  836. assert_true('dir3' in [doc['fields']['name'] for doc in documents])
  837. assert_true('query2.sql' in [doc['fields']['name'] for doc in documents])
  838. assert_true('query3.sql' in [doc['fields']['name'] for doc in documents])
  839. def test_import_owned_document(self):
  840. owned_query = Document2.objects.create(
  841. name='query.sql',
  842. type='query-hive',
  843. owner=self.user,
  844. data={'description': 'original_query'},
  845. parent_directory=self.home_dir
  846. )
  847. # Test that importing existing doc updates it and retains owner, UUID
  848. response = self.client.get('/desktop/api2/doc/export/', {'documents': json.dumps([owned_query.id]), 'format': 'json'})
  849. documents = response.content
  850. response = self.client.post('/desktop/api2/doc/import/', {'documents': documents})
  851. data = json.loads(response.content)
  852. assert_true('message' in data, data)
  853. assert_true('Installed 1 object' in data['message'], data)
  854. assert_true('count' in data)
  855. assert_equal(1, data['count'])
  856. assert_true('created_count' in data)
  857. assert_equal(0, data['created_count'])
  858. assert_true('updated_count' in data)
  859. assert_equal(1, data['updated_count'])
  860. assert_true('documents' in data)
  861. assert_true('name' in data['documents'][0])
  862. assert_equal('query.sql', data['documents'][0]['name'])
  863. assert_true('type' in data['documents'][0])
  864. assert_equal('query-hive', data['documents'][0]['type'])
  865. assert_true('owner' in data['documents'][0])
  866. assert_equal('perm_user', data['documents'][0]['owner'])
  867. assert_equal(1, Document2.objects.filter(name='query.sql').count())
  868. imported_doc = Document2.objects.get(name='query.sql')
  869. assert_equal(owned_query.uuid, imported_doc.uuid)
  870. assert_equal(owned_query.owner, imported_doc.owner)
  871. # Test that import non-existing doc creates it, sets parent to home
  872. Document2.objects.get(name='query.sql').delete()
  873. assert_equal(0, Document2.objects.filter(name='query.sql').count())
  874. response = self.client.post('/desktop/api2/doc/import/', {'documents': documents})
  875. assert_equal(1, Document2.objects.filter(name='query.sql').count())
  876. imported_doc = Document2.objects.get(name='query.sql')
  877. assert_equal(owned_query.uuid, imported_doc.uuid)
  878. assert_equal(owned_query.owner, imported_doc.owner)
  879. assert_equal(owned_query.parent_directory, imported_doc.parent_directory)
  880. def test_import_nonowned_document(self):
  881. owned_query = Document2.objects.create(
  882. name='query.sql',
  883. type='query-hive',
  884. owner=self.user,
  885. data=json.dumps({'description': 'original_query'}),
  886. parent_directory=self.home_dir
  887. )
  888. response = self.client.get('/desktop/api2/doc/export/', {'documents': json.dumps([owned_query.id]), 'format': 'json'})
  889. documents = response.content
  890. # Test that importing non-owned doc copies it, sets parent to home
  891. response = self.client_not_me.post('/desktop/api2/doc/import/', {'documents': documents})
  892. assert_equal(2, Document2.objects.filter(name='query.sql').count())
  893. imported_doc = Document2.objects.get(name='query.sql', owner=self.user_not_me)
  894. assert_true(owned_query.uuid != imported_doc.uuid)
  895. assert_equal(self.user_not_me, imported_doc.owner)
  896. assert_equal(self.not_me_home_dir.uuid, imported_doc.parent_directory.uuid)
  897. data = json.loads(response.content)
  898. assert_true('count' in data)
  899. assert_equal(1, data['count'])
  900. assert_true('created_count' in data)
  901. assert_equal(1, data['created_count'])
  902. assert_true('updated_count' in data)
  903. assert_equal(0, data['updated_count'])
  904. def test_import_with_history_dependencies(self):
  905. query1 = Document2.objects.create(name='query1.sql', type='query-hive', owner=self.user, data={},
  906. parent_directory=self.home_dir)
  907. query2 = Document2.objects.create(name='query2.sql', type='query-hive', owner=self.user, data={},
  908. parent_directory=self.home_dir, is_history=True)
  909. workflow = Document2.objects.create(name='test.wf', type='oozie-workflow2', owner=self.user, data={},
  910. parent_directory=self.home_dir)
  911. workflow.dependencies.add(query1)
  912. workflow.dependencies.add(query2)
  913. response = self.client.get('/desktop/api2/doc/export/', {'documents': json.dumps([workflow.id]), 'format': 'json'})
  914. documents = response.content
  915. # Delete previous entries from DB, so when you import it creates them
  916. query1.delete()
  917. query2.delete()
  918. workflow.delete()
  919. response = self.client_not_me.post('/desktop/api2/doc/import/', {'documents': documents})
  920. assert_true(Document2.objects.filter(name='query1.sql').exists())
  921. assert_false(Document2.objects.filter(name='query2.sql').exists())
  922. data = json.loads(response.content)
  923. assert_true('count' in data)
  924. assert_equal(2, data['count'])
  925. assert_true('created_count' in data)
  926. assert_equal(2, data['created_count'])
  927. assert_true('updated_count' in data)
  928. assert_equal(0, data['updated_count'])