def test_web_promote(self): db = self.app.database from .. import emailpw with db.transaction() as conn: user = emailpw.User('*****@*****.**', 'Tester', 'tester') user.setpw(b'secret') uid = user.id epw = conn.root.sites['localhost'].auth epw.users_by_uid[user.id] = user epw.users_by_email[user.email] = user user = emailpw.User('*****@*****.**', 'Super', 'super', True) user.setpw(b'supersecret') epw.users_by_uid[user.id] = user epw.users_by_email[user.email] = user app = self._test_app() self._login(app, '*****@*****.**', 'supersecret') # Now, we'll updata the user's admin flag r = app.put_json('/auth/users/' + uid + '/type', dict(admin=True)) vars = Vars() self.assertEqual( { 'updates': { 'generation': vars.generation, 'site': { 'boards': [], 'users': vars.users }, 'zoid': vars.zoid, 'user': vars.user } }, r.json) self.assertEqual(True, [u for u in vars.users if u['id'] == uid][0]['admin']) # Now demote r = app.put_json('/auth/users/' + uid + '/type', dict(admin=False)) vars = Vars() self.assertEqual( { 'updates': { 'generation': vars.generation, 'site': { 'boards': [], 'users': vars.users }, 'zoid': vars.zoid, 'user': vars.user } }, r.json) self.assertEqual(False, [u for u in vars.users if u['id'] == uid][0]['admin'])
def test_archive_and_restore(self): vars = Vars() with self._app.database.transaction() as conn: site = get_site(conn.root, 'localhost') site.add_board('test', '', '') board = site.boards['test'] board.new_project('p1', 0) [p1] = board.tasks board.new_task(p1.id, 't1', 1) board.new_task(p1.id, 't2', 2) task_ids = sorted(t.id for t in board.tasks) board.new_project('p2', 3) self.get('/board/test/poll') # set generation r = self.app.post('/board/test/archive/' + p1.id) updates = r.json['updates'] self.assertEqual(dict(archive_count=1, description='', name='test', title=''), updates['board']) self.assertEqual(dict(removals=vars.removals), updates['tasks']) self.assertEqual(sorted(vars.removals), task_ids) r = self.app.delete('/board/test/archive/' + p1.id) updates = r.json['updates'] self.assertEqual(dict(archive_count=0, description='', name='test', title=''), updates['board']) self.assertEqual(dict(adds=vars.restores), updates['tasks']) self.assertEqual(sorted(t['id'] for t in vars.restores), task_ids)
def setUp(self): self._app = make_app() with self._app.database.transaction() as conn: get_site(conn.root, 'localhost', 'Test site').auth = auth.Admin() self.app = self._test_app() self.vars = Vars()
def test_site_updates(self): self.site.add_board('first', 'The first one', 'Yup, the first') self.site.update_users(users) self.assertEqual( {'generation': Vars().x, 'site': self.site, 'zoid': str(u64(self.site.changes._p_oid))}, self.site.updates(0))
def test_new_project(self): self.board.new_project('first', 42, 'Do First thing') vars = Vars() self.assertEqual( dict(generation=vars.generation, tasks=dict(adds=[vars.project])), self.board.updates(self.board_generation)) self.assertEqual('first', vars.project.title) self.assertEqual(42, vars.project.order) self.assertEqual('Do First thing', vars.project.description) self.assertTrue(vars.generation > self.board_generation)
def test_update(self): self.board.update('do', 'Do things', 'Get things done') self.assertEqual( dict(name='do', title='Do things', archive_count=0, description='Get things done'), self.board.json_reduce()) vars = Vars() self.assertEqual( dict(generation=vars.generation, board=self.board, site=self.site), self.board.updates(self.board_generation)) self.assertTrue(vars.generation > self.board_generation)
def test_request_access(self, sendmail): with self.db.transaction() as conn: auth = conn.root.sites['localhost'].auth message = auth.request('*****@*****.**', 'Testy Tester', 'http://localhost') self.assertEqual("Your request is awaiting approval.", message) self.assertEqual([], sendmail.mock_calls) self.assertEqual(0, len(auth.users_by_uid)) self.assertEqual(0, len(auth.users_by_email)) self.assertEqual(2, len(auth.invites)) user = auth.invites['*****@*****.**'] # email was normalized self.assertEqual( dict(id=Vars().id, email='*****@*****.**', name="Testy Tester", nick='', admin=False), user.data) self.assertEqual(False, user.approved) self.assertEqual(0, user.resets) # Additional calls have no effect: message = auth.request('*****@*****.**', 'Testy Tester', 'http://localhost') self.assertEqual("Your request is awaiting approval.", message) self.assertEqual([], sendmail.mock_calls) self.assertEqual(0, len(auth.users_by_uid)) self.assertEqual(0, len(auth.users_by_email)) self.assertEqual(2, len(auth.invites)) user = auth.invites['*****@*****.**'] self.assertEqual( dict(id=Vars().id, email='*****@*****.**', name="Testy Tester", nick='', admin=False), user.data) self.assertEqual(False, user.approved) self.assertEqual(0, user.resets)
def test_update_invalid(self): self.board.new_project('first', 42, 'Do First thing') vars = Vars() self.assertEqual( dict(generation=vars.board_generation, tasks=dict(adds=[vars.project])), self.board.updates(self.board_generation)) with self.assertRaises(Exception): self.board.update_task(vars.project.id, order='42') with self.assertRaises(Exception): self.board.update_task(vars.project.id, foo=1) self.assertEqual(self.board.generation, vars.board_generation)
def test_rename_board(self): with self._app.database.transaction() as conn: site = get_site(conn.root, 'localhost') site.add_board('t') site.add_board('tt') self.get('/board/t/poll') site_app = self._test_app('/site/poll') tt_app = self._test_app('/site/poll') r = self.put('/board/t/', dict(name='t2')) vars = Vars() self.assertEqual(dict(board=vars.board, site=vars.site, generation=vars.g), r.json['updates']) self.assertEqual(['t2', 'tt'], [b['name'] for b in vars.site['boards']]) self.assertEqual('t2', vars.board['name'])
def test_move_into_project_wo_changing_state_or_order(self): self.board.new_project('first', 42, 'Do First thing') vars = Vars() self.assertEqual( dict(generation=vars.gen1, tasks=dict(adds=[vars.t1])), self.board.updates(self.board_generation)) self.board.new_project('second', 43, 'Do Next thing') self.assertEqual( dict(generation=vars.gen2, tasks=dict(adds=[vars.t2])), self.board.updates(vars.gen1)) self.assertTrue(vars.gen2 > vars.gen1) self.board.new_project('third', 44, 'Do 3rd thing') self.assertEqual( dict(generation=vars.gen3, tasks=dict(adds=[vars.t3])), self.board.updates(vars.gen2)) self.assertTrue(vars.gen3 > vars.gen2) # Make second project a task self.board.move(vars.t2.id, vars.t1.id, user_id='test') self.assertEqual(vars.t1.id, vars.t2.parent.id) self.assertEqual('ready', vars.t2.state.id) self.assertEqual(43, vars.t2.order) # Move t2 to an actual state: self.board.move(vars.t2.id, vars.t1.id, self._state_id('Doing'), user_id='test') # Move t2 to t3, and state and order are preserved: self.board.move(vars.t2.id, vars.t3.id, user_id='test') self.assertEqual(vars.t3.id, vars.t2.parent.id) self.assertEqual(self._state_id('Doing'), vars.t2.state.id) self.assertEqual(43, vars.t2.order) # Move t1 to new state then move to p3 and state is lost: self.board.move(vars.t1.id, state_id=self._state_id('Development'), user_id='test') self.board.move(vars.t1.id, vars.t3.id, user_id='test') self.assertEqual(vars.t3.id, vars.t1.parent.id) self.assertEqual('ready', vars.t1.state.id) self.assertEqual(42, vars.t1.order)
def test_new_task(self): vars = Vars() self.board.new_project('first', 42, 'Do First thing') self.assertEqual( dict(generation=vars.board_generation, tasks=dict(adds=[vars.project])), self.board.updates(self.board_generation)) self.board.new_task(vars.project.id, 'a sub', 43, 'A First subtask') self.assertEqual( dict(generation=vars.generation, tasks=dict(adds=[vars.task])), self.board.updates(vars.board_generation)) self.assertTrue(vars.generation > vars.board_generation) self.assertEqual('a sub', vars.task.title) self.assertEqual(43, vars.task.order) self.assertEqual('A First subtask', vars.task.description) self.assertEqual(vars.project, vars.task.parent)
def test_add_board(self): vars = Vars() generation = self.site.generation self.site.add_board('first', 'The first one', 'Yup, the first') self.assertEqual([('first', vars.board)], list(self.site.boards.items())) self.assertEqual(self.site, vars.board.site) self.assertEqual('first', vars.board.name) self.assertEqual('The first one', vars.board.title) self.assertEqual('Yup, the first', vars.board.description) self.assertTrue(self.site.generation > generation) generation = vars.board.generation self.site.add_board('second', 'The second one', 'Yup, the second') self.assertEqual(['first', 'second'], list(self.site.boards)) # The original board was updated: self.assertTrue(vars.board.generation > generation)
def test_web_update_profile(self): db = self.app.database from .. import emailpw with db.transaction() as conn: user = emailpw.User('*****@*****.**', 'Tester', 'tester') user.setpw(b'secret') epw = conn.root.sites['localhost'].auth epw.users_by_uid[user.id] = user epw.users_by_email[user.email] = user app = self._test_app() self._login(app, user.email, 'secret') # Now, we'll updata the user's profile r = app.put_json('/auth/user', dict(name='name', nick='nick', email='*****@*****.**')) vars = Vars() self.assertEqual( { 'updates': { 'generation': vars.generation, 'site': { 'boards': [], 'users': [{ 'admin': False, 'email': '*****@*****.**', 'id': vars.id, 'name': 'name', 'nick': 'nick' }] }, 'user': { 'admin': False, 'email': '*****@*****.**', 'id': vars.id, 'name': 'name', 'nick': 'nick' }, 'zoid': vars.zoid } }, r.json)
def test_remove(self): vars = Vars() with self._app.database.transaction() as conn: site = get_site(conn.root, 'localhost') site.add_board('test', '', '') board = site.boards['test'] board.new_project('p1', 0) [p1id] = [t.id for t in board.tasks] self.get('/board/test/poll') # set generation r = self.app.delete('/board/test/tasks/' + p1id) updates = r.json['updates'] self.assertEqual(dict(generation=vars.generation, tasks=dict(removals=[p1id])), r.json['updates']) with self._app.database.transaction() as conn: site = get_site(conn.root, 'localhost') board = site.boards['test'] self.assertEqual(0, len(board.tasks))
def test_update_all(self): self.board.new_project('first', 42, 'Do First thing') vars = Vars() self.assertEqual( dict(generation=vars.board_generation, tasks=dict(adds=[vars.project])), self.board.updates(self.board_generation)) data = dict( title='a project', description='It will be great', size=2, blocked="It's in the way", assigned='j1m', ) self.board.update_task(vars.project.id, **data) self.assertEqual( dict(generation=vars.generation, tasks=dict(adds=[vars.project])), self.board.updates(vars.board_generation)) self.assertTrue(vars.generation > vars.board_generation)
def test_bootstrap(self): (to, subject, message), _ = self._sent self.assertEqual("Jaci Admi <*****@*****.**>", to) self.assertEqual("Set your password for Test site", subject) self.assertTrue( message.strip().startswith("Your request to use Test site")) with self.db.transaction() as conn: auth = conn.root.sites['localhost'].auth self.assertEqual(0, len(auth.users_by_uid)) self.assertEqual(0, len(auth.users_by_email)) vars = Vars() self.assertEqual([('*****@*****.**', vars.user)], list(auth.invites.items())) self.assertEqual( dict(id=vars.id, email='*****@*****.**', name="Jaci Admi", nick='', admin=True), vars.user.data) self.assertEqual(True, vars.user.approved) self.assertEqual(1, vars.user.resets)
def test_sanitize(self): self.board.new_project('first', 42, sample_description) vars = Vars() self.assertEqual( dict(generation=vars.board_generation, tasks=dict(adds=[vars.project])), self.board.updates(self.board_generation)) self.assertEqual(sample_description_cleaned, vars.project.description) self.board.new_task(vars.project.id, 'a sub', 43, sample_description) self.assertEqual( dict(generation=vars.generation, tasks=dict(adds=[vars.task])), self.board.updates(vars.board_generation)) self.assertTrue(vars.generation > vars.board_generation) self.assertEqual(sample_description_cleaned, vars.task.description) self.board.update_task(vars.task.id, description='') self.assertEqual('', vars.task.description) self.board.update_task(vars.task.id, description=sample_description) self.assertEqual(sample_description_cleaned, vars.task.description)
def test_request_approved_user(self, sendmail, log_error): with self.db.transaction() as conn: auth = conn.root.sites['localhost'].auth for i in range(11): message = auth.request('*****@*****.**', 'Testy Tester', 'http://localhost') self.assertEqual( "An email has been sent to [email protected]" " with a link to set your password", message) if i < 8: self.assertEqual(i + 1, len(sendmail.mock_calls)) self.assertEqual(0, len(log_error.mock_calls)) (to, subject, message), _ = sendmail.call_args self.assertEqual("Jaci Admi <*****@*****.**>", to) self.assertEqual("Set your password for Test site", subject) self.assertTrue(message.strip().startswith( "Your request to use Test site")) else: self.assertEqual(8, len(sendmail.mock_calls)) self.assertEqual(i - 7, len(log_error.mock_calls)) self.assertEqual(0, len(auth.users_by_uid)) self.assertEqual(0, len(auth.users_by_email)) vars = Vars() self.assertEqual([('*****@*****.**', vars.user)], list(auth.invites.items())) self.assertEqual( dict(id=vars.id, email='*****@*****.**', name="Jaci Admi", nick='', admin=True), vars.user.data) self.assertEqual(True, vars.user.approved) self.assertEqual(i + 2, vars.user.resets)
def test_archive_and_restore_empty_feature(self, now): now.return_value = '2017-06-08T10:02:00.004' board, updates = self.board, self.updates vars = Vars() # Make an empty feature: board.new_project('p1', 42, '') self.assertEqual([vars.p1], updates()['tasks']['adds']) # Now, archive p1: self.assertEqual(0, board.archive_count) now.return_value = '2017-06-08T10:02:01.004' board.archive_feature(vars.p1.id) self.assertEqual( dict(board=board, site=board.site, tasks=dict(removals=[vars.p1.id])), updates()) self.assertEqual(1, board.archive_count) # If we asked for all updates, we'd see the expected data: self.assertEqual( dict( board=board, site=board.site, states=vars.states, tasks={}, generation=vars.generation, zoid=vars.zoid, ), board.updates(0)) # p1, which is now archived, has it's tasks in it's tasks attr: self.assertEqual([], vars.p1.tasks) # History has the archival event: self.assertEqual( dict( start='2017-06-08T10:02:01.004', state="Backlog", archived=True, ), vars.p1.history[-1]) self.assertEqual( dict( start='2017-06-08T10:02:00.004', end='2017-06-08T10:02:01.004', state="Backlog", ), vars.p1.history[-2]) # OK, now let's retore: now.return_value = '2017-06-08T10:02:02.004' board.restore_feature(vars.p1.id) self.assertEqual( dict(board=board, site=board.site, tasks=dict(adds=[vars.p1])), updates()) self.assertEqual(0, board.archive_count) # If we asked for all updates, we'd see the expected data: self.assertEqual( dict( board=board, site=board.site, states=vars.states, tasks=dict(adds=[vars.p1]), generation=vars.generationr, zoid=vars.zoid, ), board.updates(0)) # History has the archival event: self.assertEqual( dict( start='2017-06-08T10:02:02.004', state="Backlog", ), vars.p1.history[-1]) self.assertEqual( dict( start='2017-06-08T10:02:01.004', end='2017-06-08T10:02:02.004', state="Backlog", archived=True, ), vars.p1.history[-2])
def test_archive_and_restore(self, now): now.return_value = '2017-06-08T10:02:00.004' board, updates = self.board, self.updates vars = Vars() # Make some features: board.new_project('p1', 42, '') self.assertEqual([vars.p1], updates()['tasks']['adds']) board.new_task(vars.p1.id, 't1', 1) self.assertEqual([vars.t1], updates()['tasks']['adds']) board.new_task(vars.p1.id, 't2', 1) self.assertEqual([vars.t2], updates()['tasks']['adds']) # Decoys to make sure we don't work on too much: board.new_project('p2', 43, '') self.assertEqual([vars.p2], updates()['tasks']['adds']) board.new_task(vars.p2.id, 't3', 1) self.assertEqual([vars.t3], updates()['tasks']['adds']) # Move p1 to a state other than backlog board.move(vars.p1.id, state_id='Development') updates() # reset generation # Now, archive p1: self.assertEqual(0, board.archive_count) now.return_value = '2017-06-08T10:02:01.004' board.archive_feature(vars.p1.id) self.assertEqual( dict(board=board, site=board.site, tasks=dict(removals=vars.removals)), updates()) self.assertEqual(1, board.archive_count) # If we asked for all updates, we'd see the expected data: self.assertEqual( dict( board=board, site=board.site, states=vars.states, tasks=dict(adds=vars.remaining), generation=vars.generation, zoid=vars.zoid, ), board.updates(0)) self.assertEqual(['p2', 't3'], sorted(t.title for t in vars.remaining)) # p1, which is now archived, has it's tasks in it's tasks attr: self.assertEqual([vars.t1, vars.t2], sorted(vars.p1.tasks, key=lambda t: t.title)) # History has the archival event: self.assertEqual( dict( start='2017-06-08T10:02:01.004', state="Development", working=True, archived=True, ), vars.p1.history[-1]) self.assertEqual( dict( start='2017-06-08T10:02:00.004', end='2017-06-08T10:02:01.004', state="Development", working=True, ), vars.p1.history[-2]) # OK, now let's retore: now.return_value = '2017-06-08T10:02:02.004' board.restore_feature(vars.p1.id) self.assertEqual( dict(board=board, site=board.site, tasks=dict(adds=vars.restored)), updates()) self.assertEqual(0, board.archive_count) self.assertEqual([vars.p1, vars.t1, vars.t2], sorted(vars.restored, key=lambda t: t.title)) # If we asked for all updates, we'd see the expected data: self.assertEqual( dict( board=board, site=board.site, states=vars.states, tasks=dict(adds=vars.all), generation=vars.generationr, zoid=vars.zoid, ), board.updates(0)) self.assertEqual([vars.p1, vars.p2, vars.t1, vars.t2, vars.t3], sorted(vars.all, key=lambda t: t.title)) # History has the archival event: self.assertEqual( dict(start='2017-06-08T10:02:02.004', state="Development", working=True), vars.p1.history[-1]) self.assertEqual( dict( start='2017-06-08T10:02:01.004', end='2017-06-08T10:02:02.004', state="Development", working=True, archived=True, ), vars.p1.history[-2])
def test_initial_data(self): vars = Vars() self.assertEqual( dict( generation=self.board_generation, states=dict(adds=vars.states), board=self.board, site=self.site, zoid=str(u64(self.board.changes._p_oid)), ), self.board.updates(0)) self.assertEqual([{ 'complete': False, 'explode': False, 'id': 'Backlog', 'order': 0, 'task': False, 'title': 'Backlog', 'working': False }, { 'complete': False, 'explode': False, 'id': 'Ready', 'order': 1, 'task': False, 'title': 'Ready', 'working': False }, { 'complete': False, 'explode': True, 'id': 'Development', 'order': 2, 'task': False, 'title': 'Development', 'working': True }, { 'complete': False, 'explode': False, 'id': 'ready', 'order': 3, 'task': True, 'title': 'Ready', 'working': False }, { 'complete': False, 'explode': False, 'id': 'Doing', 'order': 4, 'task': True, 'title': 'Doing', 'working': True }, { 'complete': False, 'explode': False, 'id': 'Needs review', 'order': 5, 'task': True, 'title': 'Needs review', 'working': False }, { 'complete': False, 'explode': False, 'id': 'Review', 'order': 6, 'task': True, 'title': 'Review', 'working': True }, { 'complete': True, 'explode': False, 'id': 'Done', 'order': 7, 'task': True, 'title': 'Done', 'working': False }, { 'complete': False, 'explode': False, 'id': 'Acceptance', 'order': 8, 'task': False, 'title': 'Acceptance', 'working': True }, { 'complete': False, 'explode': False, 'id': 'Deploying', 'order': 9, 'task': False, 'title': 'Deploying', 'working': True }, { 'complete': False, 'explode': False, 'id': 'Deployed', 'order': 10, 'task': False, 'title': 'Deployed', 'working': False }], reduce(vars.states)) self.assertEqual(len(set(state.id for state in vars.states)), len(vars.states))
def test_move(self, now): now.return_value = '2017-06-08T10:02:00.004' self.board.new_project('first', 42, 'Do First thing') vars = Vars() self.assertEqual( dict(generation=vars.gen1, tasks=dict(adds=[vars.t1])), self.board.updates(self.board_generation)) self.board.new_project('second', 43, 'Do Next thing') self.assertEqual( dict(generation=vars.gen2, tasks=dict(adds=[vars.t2])), self.board.updates(vars.gen1)) self.assertTrue(vars.gen2 > vars.gen1) self.board.new_project('third', 44, 'Do 3rd thing') self.assertEqual( dict(generation=vars.gen3, tasks=dict(adds=[vars.t3])), self.board.updates(vars.gen2)) self.assertTrue(vars.gen3 > vars.gen2) self.assertEqual(({ 'start': '2017-06-08T10:02:00.004', 'state': 'Backlog' }, ), vars.t1.history) self.assertEqual(({ 'start': '2017-06-08T10:02:00.004', 'state': 'Backlog' }, ), vars.t2.history) self.assertEqual(({ 'start': '2017-06-08T10:02:00.004', 'state': 'Backlog' }, ), vars.t3.history) # Make second project a task now.return_value = '2017-06-08T10:02:01.004' self.board.move(vars.t2.id, vars.t1.id, self._state_id('Doing'), 1, user_id='test') self.assertEqual( dict(generation=vars.gen4, tasks=dict(adds=[vars.t2])), self.board.updates(vars.gen3)) self.assertTrue(vars.gen4 > vars.gen3) self.assertEqual(vars.t1, vars.t2.parent) self.assertEqual('Doing', vars.t2.state.title) self.assertEqual(1, vars.t2.order) self.assertEqual(( { 'start': "2017-06-08T10:02:00.004", 'end': "2017-06-08T10:02:01.004", 'state': 'Backlog' }, { 'start': "2017-06-08T10:02:01.004", 'state': "Doing", 'assigned': 'test' }, ), vars.t2.history) # Move first project to new state now.return_value = '2017-06-08T10:02:02.004' self.board.move(vars.t1.id, None, self._state_id('Development'), 2, user_id='test') self.assertEqual( dict(generation=vars.gen5, tasks=dict(adds=[vars.t1, vars.t2])), self.board.updates(vars.gen4)) self.assertTrue(vars.gen5 > vars.gen4) self.assertEqual(None, vars.t1.parent) self.assertEqual('Development', vars.t1.state.title) self.assertEqual(2, vars.t1.order) self.assertEqual(( { 'start': "2017-06-08T10:02:00.004", 'end': "2017-06-08T10:02:02.004", 'state': 'Backlog' }, { 'start': "2017-06-08T10:02:02.004", 'state': "Development", 'working': True }, ), vars.t1.history) self.assertEqual(( { 'start': "2017-06-08T10:02:00.004", 'end': "2017-06-08T10:02:01.004", 'state': 'Backlog' }, { 'start': "2017-06-08T10:02:01.004", 'end': "2017-06-08T10:02:02.004", 'state': "Doing", 'assigned': 'test' }, { 'start': "2017-06-08T10:02:02.004", 'state': "Doing", 'working': True, 'assigned': 'test' }, ), vars.t2.history) # Change order of first self.board.move(vars.t1.id, None, self._state_id('Development'), 3, user_id='test') self.assertEqual( dict(generation=vars.gen6, tasks=dict(adds=[vars.t1])), self.board.updates(vars.gen5)) self.assertTrue(vars.gen6 > vars.gen5) self.assertEqual(None, vars.t1.parent) self.assertEqual('Development', vars.t1.state.title) self.assertEqual(3, vars.t1.order) ################################################################## # Same as prev self.assertEqual(( { 'start': "2017-06-08T10:02:00.004", 'end': "2017-06-08T10:02:02.004", 'state': 'Backlog' }, { 'start': "2017-06-08T10:02:02.004", 'state': "Development", 'working': True }, ), vars.t1.history) self.assertEqual(( { 'start': "2017-06-08T10:02:00.004", 'end': "2017-06-08T10:02:01.004", 'state': 'Backlog' }, { 'start': "2017-06-08T10:02:01.004", 'end': "2017-06-08T10:02:02.004", 'state': "Doing", 'assigned': 'test' }, { 'start': "2017-06-08T10:02:02.004", 'state': "Doing", 'working': True, 'assigned': 'test' }, ), vars.t2.history) # ################################################################## # Now, some invalid moves: # Can't move to task: with self.assertRaises(Exception): self.board.move(vars.t3.id, vars.t2.id, self._state_id('Doing'), 4, user_id='test') # Can't make non-empty feature a task: with self.assertRaises(Exception): self.board.move(vars.t1.id, vars.t3.id, self._state_id('Doing'), 4, user_id='test') # Can't move to feature with task state: with self.assertRaises(Exception): self.board.move(vars.t3.id, None, self._state_id('Doing'), 4, user_id='test') # Can't move to project with to-level state: with self.assertRaises(Exception): self.board.move(vars.t3.id, vars.t1.id, self._state_id('Backlog'), 4) # finish t2 now.return_value = '2017-06-08T10:02:03.004' self.board.move(vars.t2.id, vars.t1.id, self._state_id('Done'), 1, user_id='test') self.assertEqual(( { 'start': "2017-06-08T10:02:00.004", 'end': "2017-06-08T10:02:01.004", 'state': 'Backlog' }, { 'start': "2017-06-08T10:02:01.004", 'end': "2017-06-08T10:02:02.004", 'state': "Doing", 'assigned': 'test' }, { 'start': "2017-06-08T10:02:02.004", 'end': "2017-06-08T10:02:03.004", 'state': "Doing", 'working': True, 'assigned': 'test' }, { 'start': "2017-06-08T10:02:03.004", 'state': "Done", 'complete': True, 'assigned': 'test' }, ), vars.t2.history) # We can promote a task to a project: now.return_value = '2017-06-08T10:02:04.004' self.board.move(vars.t2.id, None, self._state_id('Backlog'), 5, user_id='test') self.assertEqual( dict(generation=vars.gen7, tasks=dict(adds=[vars.t2])), self.board.updates(vars.gen6)) self.assertTrue(vars.gen7 > vars.gen6) self.assertEqual(None, vars.t2.parent) self.assertEqual('Backlog', vars.t2.state.title) self.assertEqual(5, vars.t2.order) self.assertEqual(( { 'start': "2017-06-08T10:02:00.004", 'end': "2017-06-08T10:02:01.004", 'state': 'Backlog' }, { 'start': "2017-06-08T10:02:01.004", 'end': "2017-06-08T10:02:02.004", 'state': "Doing", 'assigned': 'test' }, { 'start': "2017-06-08T10:02:02.004", 'end': "2017-06-08T10:02:03.004", 'state': "Doing", 'working': True, 'assigned': 'test' }, { 'start': "2017-06-08T10:02:03.004", 'end': "2017-06-08T10:02:04.004", 'state': "Done", 'complete': True, 'assigned': 'test' }, { 'start': "2017-06-08T10:02:04.004", 'state': "Backlog", }, ), vars.t2.history)