def process_apply_step(self, data): """ Processes the "APPLY" step of a test script, applying a user action, and checking the resulting action group's return value (if present) """ if "USER_ACTION" in data: user_actions = [useractions.from_repr(data.pop("USER_ACTION"))] else: user_actions = [ useractions.from_repr(u) for u in data.pop("USER_ACTIONS") ] expected_call_counts = data.pop("CHECK_CALL_COUNTS", None) expected_actions = data.pop("ACTIONS", {}) expected_actions.setdefault("stored", []) expected_actions.setdefault("calc", []) expected_actions.setdefault("undo", []) if data: raise ValueError("Unrecognized key %s in APPLY step" % data.popitem()[0]) self.call_counts.clear() out_actions = self.engine.apply_user_actions(user_actions) self.assertOutActions(out_actions, expected_actions) if expected_call_counts: self.assertEqual(self.call_counts, expected_call_counts) return out_actions
def test_multiple_renames(self): # Combine several renames into one bundle. self.engine.apply_user_actions([ useractions.from_repr(ua) for ua in ( ['RenameColumn', 'Students', 'firstName', 'Given_Name'], ['RenameColumn', 'Students', 'lastName', 'Family_Name'], ['RenameTable', 'Students', 'Students2'], ['RenameColumn', 'Students2', 'schoolName', 'escuela'], ['RenameColumn', 'Schools', 'name', 'schoolName'], ) ]) self.assertTableData('_grist_ACLResources', cols="subset", data=[ ['id', 'tableId', 'colIds'], [1, '*', '*'], [2, 'Students2', 'Given_Name,Family_Name'], [3, 'Students2', '*'], ]) self.assertTableData( '_grist_ACLRules', cols="subset", data=[ [ 'id', 'resource', 'aclFormula', 'permissionsText', 'userAttributes' ], [1, 1, '', '', json.dumps(user_attr1)], [ 2, 2, '( rec.escuela != # ünîcødé comment\n user.School.schoolName)', 'none', '' ], [3, 3, '', 'all', ''], ])
def test_useraction_failures(self): # Verify that when a useraction fails, we revert any changes already applied. self.load_sample(self.sample) # Simple failure: bad action (last argument should be a dict). It shouldn't cause any actions # in the first place, just raise an exception about the argument being an int. with self.assertRaisesRegexp(AttributeError, r"'int'"): self.apply_user_action(['AddColumn', 'Address', "A", 17]) # Do some successful actions, just to make sure we know what they look like. self.engine.apply_user_actions([useractions.from_repr(ua) for ua in ( ['AddColumn', 'Address', "B", {"isFormula": True}], ['UpdateRecord', 'Address', 11, {"city": "New York2"}], )]) # More complicated: here some actions should succeed, but get reverted when a later one fails. with self.assertRaisesRegexp(AttributeError, r"'int'"): self.engine.apply_user_actions([useractions.from_repr(ua) for ua in ( ['UpdateRecord', 'Address', 11, {"city": "New York3"}], ['AddColumn', 'Address', "C", {"isFormula": True}], ['AddColumn', 'Address', "D", 17] )]) with self.assertRaisesRegexp(Exception, r"non-existent record #77"): self.engine.apply_user_actions([useractions.from_repr(ua) for ua in ( ['UpdateRecord', 'Address', 11, {"city": "New York4"}], ['UpdateRecord', 'Address', 77, {"city": "Chicago"}], )]) # Make sure that no columns got added except the intentionally successful one. self.assertTableData('_grist_Tables_column', cols="subset", data=[ ["id", "colId", "type", "isFormula", "formula"], [21, "city", "Text", False, ""], [22, "B", "Any", True, ""], ], rows=lambda r: r.parentId.id == 1) # Make sure that no columns got added here either, and the only change to "New York" is the # one in the successful user-action. self.assertTableData('Address', cols="all", data=[ ["id", "city" , "B" ], [11, "New York2" , None ], [12, "Colombia" , None ], [13, "New Haven" , None ], [14, "West Haven", None ], ])
def apply_user_action(self, user_action_repr, is_undo=False): if not is_undo: log.debug("Applying user action %r" % (user_action_repr,)) if self._undo_state_tracker is not None: doc_state = self.getFullEngineData() self.call_counts.clear() out_actions = self.engine.apply_user_actions([useractions.from_repr(user_action_repr)]) out_actions.calls = self.call_counts.copy() if not is_undo and self._undo_state_tracker is not None: self._undo_state_tracker.append((doc_state, out_actions.undo[:])) return out_actions
def apply_user_actions(action_reprs, user=None): action_group = eng.apply_user_actions( [useractions.from_repr(u) for u in action_reprs], user) return eng.acl_split(action_group).to_json_obj()
def setUp(self): super(TestACLRenames, self).setUp() self.load_sample(testsamples.sample_students) # Add column to Schools to use with User Attribute. self.engine.apply_user_actions([ useractions.from_repr(ua) for ua in ( ['AddColumn', 'Schools', 'LiasonEmail', { 'type': 'Text' }], [ 'AddRecord', '_grist_ACLResources', -1, { 'tableId': '*', 'colIds': '*' } ], [ 'AddRecord', '_grist_ACLRules', None, { 'resource': -1, 'userAttributes': json.dumps(user_attr1), } ], [ 'AddRecord', '_grist_ACLResources', -2, { 'tableId': 'Students', 'colIds': 'firstName,lastName' } ], [ 'AddRecord', '_grist_ACLResources', -3, { 'tableId': 'Students', 'colIds': '*' } ], [ 'AddRecord', '_grist_ACLRules', None, { 'resource': -2, # Include comments and unicode to check that renaming respects all that. 'aclFormula': '( rec.schoolName != # ünîcødé comment\n user.School.name)', 'permissionsText': 'none', } ], [ 'AddRecord', '_grist_ACLRules', None, { 'resource': -3, 'permissionsText': 'all' } ], ) ]) # Here's what we expect to be in the ACL tables (for reference in tests below). self.assertTableData('_grist_ACLResources', cols="subset", data=[ ['id', 'tableId', 'colIds'], [1, '*', '*'], [2, 'Students', 'firstName,lastName'], [3, 'Students', '*'], ]) self.assertTableData( '_grist_ACLRules', cols="subset", data=[ [ 'id', 'resource', 'aclFormula', 'permissionsText', 'userAttributes' ], [1, 1, '', '', json.dumps(user_attr1)], [ 2, 2, '( rec.schoolName != # ünîcødé comment\n user.School.name)', 'none', '' ], [3, 3, '', 'all', ''], ])
def test_temp_row_ids(self): self.load_sample(testsamples.sample_students) out_actions = self.engine.apply_user_actions([ useractions.from_repr(ua) for ua in ( # Add a mix of records with or without temp rowIds. ['AddRecord', 'Address', None, { 'city': 'A' }], ['AddRecord', 'Address', -1, { 'city': 'B' }], [ 'BulkAddRecord', 'Address', [-3, None, -7, -10], { 'city': ['C', 'D', 'E', 'F'] } ], # -3 translates to C; the new record of -1 applies to a different table, so doesn't affect # its translation to city A. [ 'AddRecord', 'Schools', -1, { 'address': -3, 'name': 'SUNY C' } ], # Add a mix of records referring to new, existing, or null rows. [ 'BulkAddRecord', 'Schools', [None, None, None, None, None], { 'address': [-1, 11, 0, -3, -7], 'name': ['SUNY A', 'NYU', 'Xavier', 'Suny C2', 'Suny E'], } ], # Try a few updates too. ['UpdateRecord', 'Schools', 1, { 'address': -7 }], [ 'BulkUpdateRecord', 'Schools', [2, 3, 4], { 'address': [-3, -1, 11] } ], # Later temp rowIds override previous one. Here, -3 was already used. ['AddRecord', 'Address', -3, { 'city': 'G' }], [ 'AddRecord', 'Schools', None, { 'address': -3, 'name': 'SUNY G' } ], ) ]) # Test that we get the correct resulting data. self.assertTableData( 'Address', cols="subset", data=[ ["id", "city"], [11, "New York"], [12, "Colombia"], [13, "New Haven"], [14, "West Haven"], [15, "A"], [16, "B"], # was -1 [17, "C"], # was -3 [18, "D"], [19, "E"], # was -7 [20, "F"], # was -10 [21, "G"], # was -3 ]) self.assertTableData('Schools', cols="subset", data=[ ["id", "name", "address"], [1, "Columbia", 19], [2, "Columbia", 17], [3, "Yale", 16], [4, "Yale", 11], [5, "SUNY C", 17], [6, "SUNY A", 16], [7, "NYU", 11], [8, "Xavier", 0], [9, "Suny C2", 17], [10, "Suny E", 19], [11, "SUNY G", 21], ]) # Test that the actions above got properly translated. # These are same as above, except for the translated rowIds. self.assertPartialOutActions( out_actions, { "stored": [ ['AddRecord', 'Address', 15, { 'city': 'A' }], ['AddRecord', 'Address', 16, { 'city': 'B' }], [ 'BulkAddRecord', 'Address', [17, 18, 19, 20], { 'city': ['C', 'D', 'E', 'F'] } ], [ 'AddRecord', 'Schools', 5, { 'address': 17, 'name': 'SUNY C' } ], [ 'BulkAddRecord', 'Schools', [6, 7, 8, 9, 10], { 'address': [16, 11, 0, 17, 19], 'name': ['SUNY A', 'NYU', 'Xavier', 'Suny C2', 'Suny E'], } ], ['UpdateRecord', 'Schools', 1, { 'address': 19 }], [ 'BulkUpdateRecord', 'Schools', [2, 3, 4], { 'address': [17, 16, 11] } ], ['AddRecord', 'Address', 21, { 'city': 'G' }], [ 'AddRecord', 'Schools', 11, { 'address': 21, 'name': 'SUNY G' } ], # Calculated values (for Students; lookups on schools named "Columbia" and "Yale") [ "BulkUpdateRecord", "Students", [1, 2, 3, 4, 6], { "schoolCities": [ "E:C", "B:New York", "E:C", "B:New York", "B:New York" ] } ], ] })