foobara 0.5.10 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (325) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CHANGELOG.md +22 -0
  4. data/lib/foobara/all.rb +4 -2
  5. data/projects/command/src/command_pattern_implementation/concerns/command_data.rb +3 -3
  6. data/projects/command/src/command_pattern_implementation/concerns/domain_mappers.rb +2 -2
  7. data/projects/command/src/command_pattern_implementation/concerns/errors.rb +27 -27
  8. data/projects/command/src/command_pattern_implementation/concerns/errors_type.rb +7 -11
  9. data/projects/command/src/command_pattern_implementation/concerns/inputs.rb +4 -24
  10. data/projects/command/src/command_pattern_implementation/concerns/inputs_type.rb +9 -14
  11. data/projects/command/src/command_pattern_implementation/concerns/reflection.rb +7 -20
  12. data/projects/command/src/command_pattern_implementation/concerns/runtime.rb +3 -48
  13. data/projects/command/src/command_pattern_implementation/concerns/subcommands.rb +5 -5
  14. data/projects/command/src/command_pattern_implementation.rb +0 -1
  15. data/projects/command_connectors/lib/foobara/command_connectors.rb +1 -1
  16. data/projects/command_connectors/src/command_connector/concerns/desugarizers.rb +5 -5
  17. data/projects/command_connectors/src/command_connector/concerns/reflection.rb +63 -17
  18. data/projects/command_connectors/src/command_connector/request.rb +26 -10
  19. data/projects/command_connectors/src/command_connector/response.rb +2 -0
  20. data/projects/command_connectors/src/command_connector.rb +62 -58
  21. data/projects/command_connectors/src/command_registry/exposed_command.rb +7 -2
  22. data/projects/command_connectors/src/command_registry.rb +24 -18
  23. data/projects/command_connectors/src/desugarizer.rb +2 -2
  24. data/projects/command_connectors/src/desugarizers/attributes.rb +8 -8
  25. data/projects/command_connectors/src/desugarizers/auth.rb +1 -1
  26. data/projects/command_connectors/src/desugarizers/set_inputs.rb +3 -3
  27. data/projects/command_connectors/src/desugarizers/symbols_to_true.rb +2 -2
  28. data/projects/command_connectors/src/request_mutator.rb +6 -6
  29. data/projects/command_connectors/src/response_mutator.rb +6 -6
  30. data/projects/command_connectors/src/transformed_command.rb +39 -36
  31. data/projects/command_connectors/src/transformers/auth_errors_transformer.rb +2 -2
  32. data/projects/command_connectors/src/transformers/entity_to_primary_key_inputs_transformer.rb +2 -2
  33. data/projects/command_connectors/src/transformers/load_delegated_attributes_entities_pre_commit_transformer.rb +1 -1
  34. data/projects/domain_mapper/src/domain_mapper.rb +4 -4
  35. data/projects/domain_mapper/src/domain_mapper_lookups.rb +3 -3
  36. data/projects/entities/projects/detached_entity/lib/foobara/detached_entity.rb +1 -1
  37. data/projects/entities/projects/detached_entity/src/concerns/associations.rb +18 -18
  38. data/projects/entities/projects/detached_entity/src/concerns/initialization.rb +2 -2
  39. data/projects/entities/projects/detached_entity/src/concerns/primary_key.rb +4 -4
  40. data/projects/entities/projects/detached_entity/src/concerns/types.rb +2 -2
  41. data/projects/entities/projects/detached_entity/src/detached_entity_type.rb +4 -4
  42. data/projects/entities/projects/detached_entity/src/extensions/builtin_types/detached_entity/casters/primary_key.rb +1 -1
  43. data/projects/entities/projects/detached_entity/src/extensions/builtin_types/detached_entity/validators/model_instance_is_valid.rb +2 -2
  44. data/projects/entities/projects/detached_entity/src/extensions/type_declarations/handlers/registered_type_declaration/validate_primary_key_present.rb +30 -0
  45. data/projects/entities/projects/detached_entity/src/remove_sensitive_values_transformer_extensions.rb +2 -2
  46. data/projects/entities/projects/entity/lib/foobara/entity.rb +1 -1
  47. data/projects/entities/projects/entity/src/concerns/attributes.rb +6 -6
  48. data/projects/entities/projects/entity/src/concerns/callbacks.rb +1 -1
  49. data/projects/entities/projects/entity/src/concerns/initialization.rb +8 -8
  50. data/projects/entities/projects/entity/src/concerns/mutations.rb +4 -4
  51. data/projects/entities/projects/entity/src/concerns/persistence.rb +3 -3
  52. data/projects/entities/projects/entity/src/concerns/queries.rb +7 -7
  53. data/projects/entities/projects/entity/src/extensions/domain/domain_module_extension.rb +4 -4
  54. data/projects/entities/projects/entity/src/new_prepend.rb +2 -2
  55. data/projects/entities/projects/entity/src/not_found_error.rb +8 -8
  56. data/projects/entities/projects/entity/src/sensitive_value_removers/entity.rb +8 -5
  57. data/projects/entities/projects/in_memory_crud_driver_minimal/src/in_memory_minimal.rb +4 -4
  58. data/projects/entities/projects/model_attribute_helpers/lib/foobara/model_attribute_helpers.rb +0 -2
  59. data/projects/entities/projects/model_attribute_helpers/src/attribute_helper_aliases.rb +1 -1
  60. data/projects/entities/projects/model_attribute_helpers/src/attribute_helpers.rb +2 -2
  61. data/projects/entities/projects/nested_transactionable/lib/foobara/nested_transactionable.rb +5 -5
  62. data/projects/entities/projects/persistence/lib/foobara/persistence.rb +1 -1
  63. data/projects/entities/projects/persistence/src/entity_attributes_crud_driver.rb +35 -37
  64. data/projects/entities/projects/persistence/src/entity_base/transaction/concerns/entity_callback_handling.rb +25 -25
  65. data/projects/entities/projects/persistence/src/entity_base/transaction/concerns/state_transitions.rb +8 -8
  66. data/projects/entities/projects/persistence/src/entity_base/transaction/concerns/transaction_tracking.rb +1 -1
  67. data/projects/entities/projects/persistence/src/entity_base/transaction.rb +9 -9
  68. data/projects/entities/projects/persistence/src/entity_base/transaction_table/concerns/record_tracking.rb +4 -4
  69. data/projects/entities/projects/persistence/src/entity_base/transaction_table.rb +52 -52
  70. data/projects/entities/projects/persistence/src/entity_base.rb +7 -7
  71. data/projects/entities/projects/persistence/src/persistence.rb +23 -23
  72. data/projects/entities/projects/weak_object_set/src/weak_object_set.rb +16 -16
  73. data/projects/entities_plumbing/lib/foobara/entities_plumbing.rb +6 -2
  74. data/projects/entities_plumbing/src/extensions/command_pattern_implementation/concerns/entities.rb +21 -5
  75. data/projects/entities_plumbing/src/extensions/command_pattern_implementation/concerns/entity_errors_type.rb +23 -0
  76. data/projects/entities_plumbing/src/extensions/command_pattern_implementation/concerns/entity_inputs.rb +33 -0
  77. data/projects/entities_plumbing/src/extensions/command_pattern_implementation/concerns/entity_reflection.rb +39 -0
  78. data/projects/entities_plumbing/src/extensions/command_pattern_implementation/concerns/runtime.rb +39 -0
  79. data/projects/manifest/src/base_manifest.rb +9 -9
  80. data/projects/manifest/src/model.rb +4 -4
  81. data/projects/manifest/src/type.rb +3 -3
  82. data/projects/manifest/src/type_declaration.rb +4 -4
  83. data/projects/model_plumbing/lib/foobara/model_plumbing.rb +2 -0
  84. data/projects/model_plumbing/src/extensions/command_pattern_implementation/concerns/model_inputs_type.rb +35 -0
  85. data/projects/typesystem/projects/builtin_types/lib/foobara/builtin_types.rb +2 -1
  86. data/projects/typesystem/projects/builtin_types/src/builtin_types.rb +8 -8
  87. data/projects/typesystem/projects/builtin_types/src/duck/supported_validators/one_of/type_declaration_extension/extend_registered_type_declaration/desugarizers/module_desugarizer.rb +2 -2
  88. data/projects/typesystem/projects/builtin_types/src/email/validator_base.rb +4 -4
  89. data/projects/typesystem/projects/callback/src/block/concerns/block_parameter_required.rb +2 -2
  90. data/projects/typesystem/projects/callback/src/block/concerns/keyword_argumentable_block.rb +2 -2
  91. data/projects/typesystem/projects/callback/src/block/concerns/single_argument_block.rb +2 -2
  92. data/projects/typesystem/projects/callback/src/block.rb +4 -4
  93. data/projects/typesystem/projects/callback/src/registry/base.rb +10 -10
  94. data/projects/typesystem/projects/callback/src/registry/conditioned.rb +2 -2
  95. data/projects/typesystem/projects/callback/src/registry/multiple_action.rb +6 -6
  96. data/projects/typesystem/projects/callback/src/runner.rb +4 -4
  97. data/projects/typesystem/projects/callback/src/set.rb +4 -4
  98. data/projects/typesystem/projects/common/src/data_path.rb +14 -14
  99. data/projects/typesystem/projects/common/src/error.rb +11 -11
  100. data/projects/typesystem/projects/common/src/error_collection.rb +14 -14
  101. data/projects/typesystem/projects/common/src/error_key.rb +5 -3
  102. data/projects/typesystem/projects/common/src/outcome.rb +5 -5
  103. data/projects/typesystem/projects/common/src/possible_error.rb +2 -2
  104. data/projects/typesystem/projects/concerns/src/concern.rb +3 -3
  105. data/projects/typesystem/projects/delegate/src/extensions/module.rb +4 -4
  106. data/projects/typesystem/projects/domain/lib/foobara/domain.rb +2 -2
  107. data/projects/typesystem/projects/domain/src/domain.rb +5 -5
  108. data/projects/typesystem/projects/domain/src/domain_module_extension.rb +22 -22
  109. data/projects/typesystem/projects/domain/src/extensions/foobara.rb +14 -6
  110. data/projects/typesystem/projects/domain/src/module_extension.rb +4 -4
  111. data/projects/typesystem/projects/domain/src/organization.rb +6 -6
  112. data/projects/typesystem/projects/enumerated/src/accessors.rb +4 -4
  113. data/projects/typesystem/projects/enumerated/src/values.rb +14 -14
  114. data/projects/{entities → typesystem}/projects/model/lib/foobara/model.rb +1 -1
  115. data/projects/{entities → typesystem}/projects/model/src/concerns/classes.rb +4 -4
  116. data/projects/{entities → typesystem}/projects/model/src/concerns/types.rb +5 -5
  117. data/projects/{entities → typesystem}/projects/model/src/extensions/builtin_types/model/casters/hash.rb +1 -1
  118. data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/attributes_handler_desugarizer.rb +2 -2
  119. data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/model_class_desugarizer.rb +6 -6
  120. data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/to_type_transformer.rb +4 -4
  121. data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration.rb +2 -2
  122. data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/registered_type_declaration/model_class_desugarizer.rb +6 -10
  123. data/projects/{entities → typesystem}/projects/model/src/model.rb +13 -13
  124. data/projects/{entities → typesystem}/projects/model/src/sensitive_value_removers/model.rb +1 -1
  125. data/projects/typesystem/projects/namespace/src/ambiguous_registry.rb +5 -5
  126. data/projects/typesystem/projects/namespace/src/base_registry.rb +8 -8
  127. data/projects/typesystem/projects/namespace/src/is_namespace.rb +19 -19
  128. data/projects/typesystem/projects/namespace/src/namespace/lookup_mode.rb +2 -2
  129. data/projects/typesystem/projects/namespace/src/namespace.rb +5 -5
  130. data/projects/typesystem/projects/namespace/src/namespace_helpers.rb +4 -4
  131. data/projects/typesystem/projects/namespace/src/prefixless_registry.rb +3 -3
  132. data/projects/typesystem/projects/namespace/src/scoped.rb +7 -7
  133. data/projects/typesystem/projects/project/src/foobara.rb +13 -7
  134. data/projects/typesystem/projects/project/src/project.rb +1 -1
  135. data/projects/typesystem/projects/state_machine/src/callbacks.rb +14 -14
  136. data/projects/typesystem/projects/state_machine/src/state_machine.rb +2 -2
  137. data/projects/typesystem/projects/state_machine/src/sugar.rb +3 -3
  138. data/projects/typesystem/projects/type_declarations/lib/foobara/type_declarations.rb +1 -1
  139. data/projects/typesystem/projects/type_declarations/src/attributes.rb +2 -2
  140. data/projects/typesystem/projects/type_declarations/src/attributes_transformers/from_yaml.rb +2 -2
  141. data/projects/typesystem/projects/type_declarations/src/attributes_transformers/only.rb +2 -2
  142. data/projects/typesystem/projects/type_declarations/src/attributes_transformers/reject.rb +2 -2
  143. data/projects/typesystem/projects/type_declarations/src/attributes_transformers/set.rb +4 -4
  144. data/projects/typesystem/projects/type_declarations/src/desugarizer.rb +2 -2
  145. data/projects/typesystem/projects/type_declarations/src/dsl/attributes.rb +9 -9
  146. data/projects/typesystem/projects/type_declarations/src/error_extension.rb +6 -6
  147. data/projects/typesystem/projects/type_declarations/src/handlers/extend_array_type_declaration/array_desugarizer.rb +3 -3
  148. data/projects/typesystem/projects/type_declarations/src/handlers/extend_array_type_declaration/element_type_declaration_desugarizer.rb +2 -2
  149. data/projects/typesystem/projects/type_declarations/src/handlers/extend_array_type_declaration/type_set_to_array_desugarizer.rb +2 -2
  150. data/projects/typesystem/projects/type_declarations/src/handlers/extend_attributes_type_declaration/element_type_declarations_desugarizer.rb +2 -2
  151. data/projects/typesystem/projects/type_declarations/src/handlers/extend_registered_type_declaration/to_type_transformer.rb +2 -2
  152. data/projects/typesystem/projects/type_declarations/src/handlers/extend_registered_type_declaration.rb +2 -2
  153. data/projects/typesystem/projects/type_declarations/src/handlers/extend_tuple_type_declaration/array_desugarizer.rb +2 -2
  154. data/projects/typesystem/projects/type_declarations/src/handlers/registered_type_declaration.rb +4 -3
  155. data/projects/typesystem/projects/type_declarations/src/remove_sensitive_values_transformer.rb +3 -3
  156. data/projects/typesystem/projects/type_declarations/src/type_builder.rb +5 -5
  157. data/projects/typesystem/projects/type_declarations/src/type_declaration.rb +7 -1
  158. data/projects/typesystem/projects/type_declarations/src/type_declaration_handler.rb +13 -13
  159. data/projects/typesystem/projects/type_declarations/src/type_declaration_handler_registry.rb +2 -2
  160. data/projects/typesystem/projects/type_declarations/src/type_declaration_validator.rb +2 -2
  161. data/projects/typesystem/projects/type_declarations/src/type_declarations.rb +2 -2
  162. data/projects/typesystem/projects/type_declarations/src/with_registries.rb +2 -2
  163. data/projects/typesystem/projects/types/lib/foobara/types.rb +0 -2
  164. data/projects/typesystem/projects/types/src/extensions/error.rb +5 -5
  165. data/projects/typesystem/projects/types/src/type/concerns/reflection.rb +22 -22
  166. data/projects/typesystem/projects/types/src/type/concerns/supported_processor_registration.rb +4 -4
  167. data/projects/typesystem/projects/types/src/type.rb +25 -25
  168. data/projects/typesystem/projects/value/src/caster.rb +11 -11
  169. data/projects/typesystem/projects/value/src/data_error.rb +1 -1
  170. data/projects/typesystem/projects/value/src/mutator.rb +3 -3
  171. data/projects/typesystem/projects/value/src/processor/casting.rb +6 -6
  172. data/projects/typesystem/projects/value/src/processor/pipeline.rb +2 -2
  173. data/projects/typesystem/projects/value/src/processor/runner.rb +1 -1
  174. data/projects/typesystem/projects/value/src/processor/selection.rb +3 -3
  175. data/projects/typesystem/projects/value/src/processor.rb +23 -23
  176. data/projects/typesystem/projects/value/src/transformer.rb +5 -5
  177. data/projects/typesystem/projects/value/src/validator.rb +3 -3
  178. data/version.rb +2 -2
  179. metadata +44 -160
  180. data/projects/command_connectors/Guardfile +0 -6
  181. data/projects/command_connectors/spec/allowed_rules_spec.rb +0 -77
  182. data/projects/command_connectors/spec/ambiguous_lookups_spec.rb +0 -143
  183. data/projects/command_connectors/spec/auth_mappers_spec.rb +0 -201
  184. data/projects/command_connectors/spec/command_connector_spec.rb +0 -2460
  185. data/projects/command_connectors/spec/command_registry_spec.rb +0 -9
  186. data/projects/command_connectors/spec/commands/describe_spec.rb +0 -83
  187. data/projects/command_connectors/spec/commands/ping_spec.rb +0 -14
  188. data/projects/command_connectors/spec/commands/query_git_commit_info_spec.rb +0 -55
  189. data/projects/command_connectors/spec/fixtures/command_connectors/manifest_with_errors_with_missing_command_parents.yaml +0 -1662
  190. data/projects/command_connectors/spec/not_found_error_spec.rb +0 -17
  191. data/projects/command_connectors/spec/pre_commit_transformers/load_atoms_pre_commit_transformer_spec.rb +0 -108
  192. data/projects/command_connectors/spec/request_spec.rb +0 -118
  193. data/projects/command_connectors/spec/serializer_spec.rb +0 -9
  194. data/projects/command_connectors/spec/serializers/aggregate_serializer_spec.rb +0 -45
  195. data/projects/command_connectors/spec/serializers/atomic_serializer_spec.rb +0 -68
  196. data/projects/command_connectors/spec/serializers/entities_to_primary_keys_serializer_spec.rb +0 -36
  197. data/projects/command_connectors/spec/serializers/json_serializer_spec.rb +0 -22
  198. data/projects/command_connectors/spec/serializers/noop_serializer_spec.rb +0 -22
  199. data/projects/command_connectors/spec/serializers/yaml_serializer_spec.rb +0 -22
  200. data/projects/command_connectors/spec/spec_helper.rb +0 -56
  201. data/projects/command_connectors/spec/support/rubyprof.rb +0 -32
  202. data/projects/command_connectors/spec/support/term_trap.rb +0 -6
  203. data/projects/command_connectors/spec/transformers/entity_to_primary_key_inputs_transformer_spec.rb +0 -119
  204. data/projects/entities/Guardfile +0 -6
  205. data/projects/entities/spec/builtin_types/detached_entity_spec.rb +0 -300
  206. data/projects/entities/spec/builtin_types/entity_spec.rb +0 -501
  207. data/projects/entities/spec/builtin_types/model_spec.rb +0 -420
  208. data/projects/entities/spec/detached_entity/casting_spec.rb +0 -31
  209. data/projects/entities/spec/entity/concerns/associations_spec.rb +0 -73
  210. data/projects/entities/spec/entity/concerns/attribute_helpers_spec.rb +0 -220
  211. data/projects/entities/spec/entity/concerns/callbacks_spec.rb +0 -61
  212. data/projects/entities/spec/entity/concerns/initialization_spec.rb +0 -213
  213. data/projects/entities/spec/entity/concerns/mutations_spec.rb +0 -38
  214. data/projects/entities/spec/entity/concerns/queries_spec.rb +0 -184
  215. data/projects/entities/spec/entity/entity_spec.rb +0 -240
  216. data/projects/entities/spec/entity/extending_existing_spec.rb +0 -137
  217. data/projects/entities/spec/entity/extensions/domain_module_extension_spec.rb +0 -42
  218. data/projects/entities/spec/entity/from_type_declaration_spec.rb +0 -34
  219. data/projects/entities/spec/entity/that_owns_spec.rb +0 -243
  220. data/projects/entities/spec/entity/weak_object_set_spec.rb +0 -91
  221. data/projects/entities/spec/model/model_spec.rb +0 -135
  222. data/projects/entities/spec/model/types_spec.rb +0 -397
  223. data/projects/entities/spec/nested_transactionable/nested_transactionable_spec.rb +0 -67
  224. data/projects/entities/spec/persistence/entity_attributes_crud_drivers/in_memory_minimal_spec.rb +0 -13
  225. data/projects/entities/spec/persistence/entity_base/transaction_spec.rb +0 -509
  226. data/projects/entities/spec/persistence/entity_base/transaction_table_spec.rb +0 -58
  227. data/projects/entities/spec/persistence/persistence_spec.rb +0 -148
  228. data/projects/entities/spec/spec_helper.rb +0 -54
  229. data/projects/entities/spec/support/rubyprof.rb +0 -32
  230. data/projects/entities/spec/support/term_trap.rb +0 -6
  231. data/projects/entities/spec/type_declarations/sensitive_type_removers_spec.rb +0 -90
  232. data/projects/entities_plumbing/Guardfile +0 -6
  233. data/projects/entities_plumbing/spec/auth_mappers_spec.rb +0 -159
  234. data/projects/entities_plumbing/spec/spec_helper.rb +0 -55
  235. data/projects/entities_plumbing/spec/support/rubyprof.rb +0 -32
  236. data/projects/entities_plumbing/spec/support/term_trap.rb +0 -6
  237. data/projects/entities_plumbing/spec/transaction_spec.rb +0 -534
  238. data/projects/manifest/Guardfile +0 -6
  239. data/projects/manifest/spec/associations_spec.rb +0 -67
  240. data/projects/manifest/spec/manifest_spec.rb +0 -382
  241. data/projects/manifest/spec/model_spec.rb +0 -126
  242. data/projects/manifest/spec/spec_helper.rb +0 -54
  243. data/projects/manifest/spec/type_declaration_spec.rb +0 -39
  244. data/projects/manifest/spec/type_spec.rb +0 -30
  245. data/projects/typesystem/spec/builtin_types/allow_nil_spec.rb +0 -138
  246. data/projects/typesystem/spec/builtin_types/array_spec.rb +0 -140
  247. data/projects/typesystem/spec/builtin_types/associative_array_spec.rb +0 -228
  248. data/projects/typesystem/spec/builtin_types/attributes_spec.rb +0 -490
  249. data/projects/typesystem/spec/builtin_types/big_decimal_spec.rb +0 -42
  250. data/projects/typesystem/spec/builtin_types/boolean_spec.rb +0 -43
  251. data/projects/typesystem/spec/builtin_types/class_type_desugarizer_spec.rb +0 -17
  252. data/projects/typesystem/spec/builtin_types/custom_type_spec.rb +0 -430
  253. data/projects/typesystem/spec/builtin_types/date_spec.rb +0 -37
  254. data/projects/typesystem/spec/builtin_types/datetime_spec.rb +0 -49
  255. data/projects/typesystem/spec/builtin_types/email_spec.rb +0 -44
  256. data/projects/typesystem/spec/builtin_types/float_spec.rb +0 -59
  257. data/projects/typesystem/spec/builtin_types/instance_of_spec.rb +0 -75
  258. data/projects/typesystem/spec/builtin_types/one_of_spec.rb +0 -73
  259. data/projects/typesystem/spec/builtin_types/string_spec.rb +0 -117
  260. data/projects/typesystem/spec/builtin_types/symbol_spec.rb +0 -24
  261. data/projects/typesystem/spec/builtin_types/tuple_spec.rb +0 -125
  262. data/projects/typesystem/spec/callback/callback_spec.rb +0 -155
  263. data/projects/typesystem/spec/callback/registry/conditioned_spec.rb +0 -152
  264. data/projects/typesystem/spec/callback/registry/multiple_action_spec.rb +0 -144
  265. data/projects/typesystem/spec/callback/registry/single_action_spec.rb +0 -114
  266. data/projects/typesystem/spec/common/data_path_spec.rb +0 -268
  267. data/projects/typesystem/spec/common/error_collection_spec.rb +0 -77
  268. data/projects/typesystem/spec/common/error_key_spec.rb +0 -56
  269. data/projects/typesystem/spec/common/outcome_spec.rb +0 -65
  270. data/projects/typesystem/spec/common/possible_error_spec.rb +0 -17
  271. data/projects/typesystem/spec/concerns/concern_spec.rb +0 -122
  272. data/projects/typesystem/spec/enumerated/accessors_spec.rb +0 -182
  273. data/projects/typesystem/spec/enumerated/enumerated_spec.rb +0 -32
  274. data/projects/typesystem/spec/enumerated/values_spec.rb +0 -67
  275. data/projects/typesystem/spec/foobara/foobara_spec.rb +0 -45
  276. data/projects/typesystem/spec/namespace/ambiguous_registry_spec.rb +0 -70
  277. data/projects/typesystem/spec/namespace/foobara_simulation_spec.rb +0 -254
  278. data/projects/typesystem/spec/namespace/is_namespace_spec.rb +0 -103
  279. data/projects/typesystem/spec/namespace/namespace_helpers_spec.rb +0 -67
  280. data/projects/typesystem/spec/namespace/namespace_spec.rb +0 -335
  281. data/projects/typesystem/spec/namespace/prefixless_registry_spec.rb +0 -30
  282. data/projects/typesystem/spec/namespace/unambiguous_registry_spec.rb +0 -50
  283. data/projects/typesystem/spec/spec_helper.rb +0 -52
  284. data/projects/typesystem/spec/state_machine/callbacks_spec.rb +0 -144
  285. data/projects/typesystem/spec/state_machine/state_machine_spec.rb +0 -224
  286. data/projects/typesystem/spec/state_machine/target_attribute_spec.rb +0 -46
  287. data/projects/typesystem/spec/support/rubyprof.rb +0 -32
  288. data/projects/typesystem/spec/support/term_trap.rb +0 -6
  289. data/projects/typesystem/spec/type_declarations/attributes_spec.rb +0 -14
  290. data/projects/typesystem/spec/type_declarations/attributes_transformer_spec.rb +0 -95
  291. data/projects/typesystem/spec/type_declarations/dsl/attributes_spec.rb +0 -107
  292. data/projects/typesystem/spec/type_declarations/handlers/extend_registered_type_declaration_spec.rb +0 -13
  293. data/projects/typesystem/spec/type_declarations/sensitive_type_removers_spec.rb +0 -210
  294. data/projects/typesystem/spec/type_declarations/type_builder_spec.rb +0 -47
  295. data/projects/typesystem/spec/type_declarations/type_declaration_spec.rb +0 -252
  296. data/projects/typesystem/spec/type_declarations/type_declarations_spec.rb +0 -11
  297. data/projects/typesystem/spec/type_declarations/typed_transformer_spec.rb +0 -65
  298. data/projects/typesystem/spec/types/sensitive_spec.rb +0 -36
  299. data/projects/typesystem/spec/types/type_spec.rb +0 -102
  300. data/projects/typesystem/spec/value/caster_spec.rb +0 -23
  301. data/projects/typesystem/spec/value/processor/runner_spec.rb +0 -34
  302. data/projects/typesystem/spec/value/processor/selection_spec.rb +0 -71
  303. data/projects/typesystem/spec/value/processor_spec.rb +0 -76
  304. data/projects/typesystem/spec/value/transformer_spec.rb +0 -27
  305. /data/projects/{command/src → entities_plumbing/src/extensions}/command_pattern_implementation/concerns/transactions.rb +0 -0
  306. /data/projects/{entities → typesystem}/projects/model/src/concerns/aliases.rb +0 -0
  307. /data/projects/{entities → typesystem}/projects/model/src/concerns/reflection.rb +0 -0
  308. /data/projects/{entities → typesystem}/projects/model/src/extensions/builtin_types/model/supported_transformers/mutable.rb +0 -0
  309. /data/projects/{entities → typesystem}/projects/model/src/extensions/builtin_types/model/validators/model_instance_is_valid.rb +0 -0
  310. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/array_with_symbolic_elements.rb +0 -0
  311. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/delegates_desugarizer.rb +0 -0
  312. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/delegates_validator.rb +0 -0
  313. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/hash_desugarizer.rb +0 -0
  314. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/move_private_from_element_types_to_root.rb +0 -0
  315. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/symbolize_private.rb +0 -0
  316. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/valid_attribute_names.rb +0 -0
  317. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration.rb +0 -0
  318. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/hash_desugarizer.rb +0 -0
  319. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/model_class_type_desugarizer.rb +0 -0
  320. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/mutable_validator.rb +0 -0
  321. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/normalize_mutable_attributes_desugarizer.rb +0 -0
  322. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration/to_type_transformer.rb +0 -0
  323. /data/projects/{entities → typesystem}/projects/model/src/extensions/type_declarations/lazy_element_types/model.rb +0 -0
  324. /data/projects/{entities → typesystem}/projects/model/src/sensitive_type_removers/extended_model.rb +0 -0
  325. /data/projects/{entities → typesystem}/projects/model/src/sensitive_type_removers/model.rb +0 -0
@@ -1,2460 +0,0 @@
1
- RSpec.describe Foobara::CommandConnector do
2
- after do
3
- Foobara.reset_alls
4
- end
5
-
6
- let(:command_class) do
7
- sc = ->(*args, &block) { stub_class(*args, &block) }
8
-
9
- stub_class(:ComputeExponent, Foobara::Command) do
10
- error_klass = sc.call(:SomeRuntimeError, Foobara::RuntimeError) do
11
- context :duck
12
- end
13
-
14
- input_error_class = sc.call(:SomeInputError, Foobara::Value::DataError) do
15
- class << self
16
- def context_type_declaration
17
- :duck
18
- end
19
- end
20
- end
21
-
22
- possible_error error_klass
23
- possible_input_error :base, input_error_class
24
-
25
- inputs exponent: :integer,
26
- base: :integer
27
- result :integer
28
-
29
- attr_accessor :exponential
30
-
31
- def execute
32
- compute
33
-
34
- exponential
35
- end
36
-
37
- def compute
38
- self.exponential = 1
39
-
40
- exponent.times do
41
- self.exponential *= base
42
- end
43
- end
44
- end
45
- end
46
-
47
- let(:command_connector) do
48
- described_class.new(authenticator:, default_serializers:, default_pre_commit_transformers:)
49
- end
50
-
51
- let(:command_registry) { command_connector.command_registry }
52
-
53
- let(:authenticator) { nil }
54
- let(:default_serializers) do
55
- [Foobara::CommandConnectors::Serializers::ErrorsSerializer,
56
- Foobara::CommandConnectors::Serializers::JsonSerializer]
57
- end
58
- let(:default_pre_commit_transformers) { nil }
59
-
60
- let(:base) { 2 }
61
- let(:exponent) { 3 }
62
-
63
- let(:response) { command_connector.run(full_command_name:, action:, inputs:) }
64
- let(:parsed_response) { JSON.parse(response.body) }
65
-
66
- let(:action) { "run" }
67
- let(:full_command_name) { "ComputeExponent" }
68
- let(:inputs) do
69
- {
70
- base:,
71
- exponent:
72
- }
73
- end
74
- let(:inputs_transformers) { nil }
75
- let(:result_transformers) { nil }
76
- let(:inputs_transformers_sugar) { nil }
77
- let(:result_transformers_sugar) { nil }
78
- let(:errors_transformers) { nil }
79
- let(:pre_commit_transformers) { nil }
80
- let(:serializers) { nil }
81
- let(:response_mutators) { nil }
82
- let(:request_mutators) { nil }
83
- let(:allowed_rule) { nil }
84
- let(:allowed_rules) { nil }
85
- let(:requires_authentication) { nil }
86
- let(:capture_unknown_error) { false }
87
- let(:aggregate_entities) { nil }
88
- let(:atomic_entities) { nil }
89
-
90
- describe "#connect" do
91
- context "when command is connected before it is loaded" do
92
- let(:command_class) do
93
- stub_module :SomeOrg do
94
- foobara_organization!
95
- end
96
-
97
- stub_module("SomeOrg::SomeDomain") do
98
- foobara_domain!
99
- end
100
-
101
- stub_class "SomeOrg::SomeDomain::SomeCommand", Foobara::Command do
102
- description "just some command"
103
- end
104
- end
105
-
106
- it "registers the command" do
107
- command_connector.connect("SomeOrg::SomeDomain::SomeCommand")
108
-
109
- command_class
110
-
111
- exposed_commands = command_connector.all_exposed_commands
112
- expect(exposed_commands.size).to eq(1)
113
- exposed_command = exposed_commands.first
114
- transformed_command = exposed_command.transformed_command_class
115
-
116
- expect(transformed_command.command_class).to eq(command_class)
117
- expect(transformed_command.new.inputs).to eq({})
118
- end
119
- end
120
-
121
- context "when command is in an organization" do
122
- let!(:org_module) do
123
- stub_module :SomeOrg do
124
- foobara_organization!
125
- end
126
- end
127
-
128
- let!(:domain_module) do
129
- stub_module("SomeOrg::SomeDomain") do
130
- foobara_domain!
131
- end
132
- end
133
-
134
- let!(:command_class) do
135
- stub_module "SomeOtherOrg" do
136
- foobara_organization!
137
- end
138
- stub_module "SomeOtherOrg::SomeOtherDomain" do
139
- foobara_domain!
140
- end
141
- stub_class "SomeOtherOrg::SomeOtherDomain::SomeOtherCommand", Foobara::Command do
142
- inputs email: :email
143
- end
144
- stub_class "SomeOrg::SomeDomain::SomeCommand", Foobara::Command do
145
- description "just some command"
146
- depends_on SomeOtherOrg::SomeOtherDomain::SomeOtherCommand
147
- end
148
- end
149
-
150
- it "registers the command" do
151
- command_connector.connect(org_module)
152
-
153
- expect(command_connector.command_connected?(SomeOrg::SomeDomain::SomeCommand)).to be true
154
-
155
- exposed_commands = command_connector.all_exposed_commands
156
- expect(exposed_commands.size).to eq(1)
157
- exposed_command = exposed_commands.first
158
-
159
- expect(exposed_command.full_command_symbol).to eq(:"some_org::some_domain::some_command")
160
-
161
- transformed_command = exposed_command.transformed_command_class
162
- expect(transformed_command.command_class).to eq(command_class)
163
-
164
- command_classes = []
165
-
166
- command_registry.each_transformed_command_class do |klass|
167
- command_classes << klass
168
- end
169
-
170
- expect(command_classes).to eq([transformed_command])
171
- expect(command_registry.all_transformed_command_classes).to eq([transformed_command])
172
- end
173
-
174
- context "when registering via domain" do
175
- before do
176
- command_connector.connect(domain_module)
177
- end
178
-
179
- it "registers the command" do
180
- transformed_commands = command_connector.all_transformed_command_classes
181
- expect(transformed_commands.size).to eq(1)
182
- expect(transformed_commands.first.command_class).to eq(command_class)
183
- end
184
-
185
- context "when generating a manifest" do
186
- it "includes the organization" do
187
- manifest = command_connector.foobara_manifest
188
-
189
- expect(manifest[:organization].keys).to contain_exactly(:SomeOrg, :global_organization)
190
- expect(manifest[:command][:"SomeOrg::SomeDomain::SomeCommand"][:description]).to eq("just some command")
191
- end
192
- end
193
- end
194
- end
195
-
196
- context "when connecting a command that returns sensitive data" do
197
- before do
198
- stub_module :SomeOrg do
199
- foobara_organization!
200
- end
201
-
202
- stub_module("SomeOrg::SomeDomain") do
203
- foobara_domain!
204
- end
205
-
206
- stub_class "SomeOrg::SomeDomain::User", Foobara::Entity do
207
- attributes do
208
- id :integer
209
- password :string, :allow_nil, :sensitive
210
- username :string, :required
211
- foo :array do
212
- bar :string, :sensitive, :allow_nil
213
- baz :string
214
- end
215
- end
216
-
217
- primary_key :id
218
- end
219
-
220
- stub_class "SomeOrg::SomeDomain::CreateUser", Foobara::Command do
221
- inputs do
222
- username :string, :required
223
- password :string, :sensitive
224
- foo :array do
225
- bar :string, :sensitive, :allow_nil
226
- baz :string
227
- end
228
- end
229
-
230
- result SomeOrg::SomeDomain::User
231
-
232
- def execute
233
- SomeOrg::SomeDomain::User.create(inputs)
234
- end
235
- end
236
-
237
- stub_class "SomeOrg::SomeDomain::Login", Foobara::Command do
238
- inputs do
239
- username :string, :required
240
- password :string, :required, :sensitive
241
- end
242
-
243
- result :string
244
- end
245
- end
246
-
247
- it "does not include sensitive input types in the manifest" do
248
- command_connector.connect(SomeOrg::SomeDomain::CreateUser)
249
- command_connector.connect(SomeOrg::SomeDomain::Login)
250
-
251
- manifest = command_connector.foobara_manifest
252
-
253
- user_manifest = manifest[:type][:"SomeOrg::SomeDomain::User"]
254
- declaration_data = user_manifest[:declaration_data]
255
-
256
- expect(
257
- declaration_data[:attributes_declaration][:element_type_declarations].keys
258
- ).to contain_exactly(:username, :id, :foo)
259
- end
260
-
261
- context "when running a command that returns sensitive values" do
262
- let(:full_command_name) { "SomeOrg::SomeDomain::CreateUser" }
263
- let(:inputs) do
264
- {
265
- username: "foo",
266
- password: "bar",
267
- foo: [{ bar: "bar", baz: "baz" }, { baz: "baz2" }]
268
- }
269
- end
270
-
271
- let(:serializers) { Foobara::CommandConnectors::Serializers::AggregateSerializer }
272
- let(:pre_commit_transformers) { Foobara::CommandConnectors::Transformers::LoadAggregatesPreCommitTransformer }
273
-
274
- before do
275
- Foobara::Persistence.default_crud_driver = Foobara::Persistence::CrudDrivers::InMemory.new
276
- command_connector.connect(SomeOrg::SomeDomain::CreateUser, serializers:, pre_commit_transformers:)
277
- end
278
-
279
- it "does not include sensitive output values in the result" do
280
- expect(response.status).to be(0)
281
- expect(response.error).to be_nil
282
- expect(JSON.parse(response.body)).to eq(
283
- "id" => 1,
284
- "username" => "foo",
285
- "foo" => [
286
- { "baz" => "baz" },
287
- { "baz" => "baz2" }
288
- ]
289
- )
290
- end
291
-
292
- context "when command can return a thunk" do
293
- let(:serializers) { [] }
294
- let(:full_command_name) { "SomeOrg::SomeDomain::FindUser" }
295
- let(:user) do
296
- SomeOrg::SomeDomain::CreateUser.run!(
297
- username: "foo",
298
- password: "bar",
299
- foo: [{ bar: "bar", baz: "baz" }, { baz: "baz2" }]
300
- )
301
- end
302
- let(:user_id) do
303
- user.id
304
- end
305
- let(:some_other_user) do
306
- SomeOrg::SomeDomain::CreateUser.run!(
307
- username: "baz",
308
- password: "baz",
309
- foo: [{ bar: "baz", baz: "baz" }, { baz: "baz" }]
310
- )
311
- end
312
- let(:inputs) do
313
- { user: user_id }
314
- end
315
- let(:pre_commit_transformers) { [] }
316
-
317
- before do
318
- some_other_user_id = some_other_user.id
319
-
320
- stub_class "SomeOrg::SomeDomain::FindUser", Foobara::Command do
321
- inputs do
322
- user SomeOrg::SomeDomain::User
323
- end
324
-
325
- result SomeOrg::SomeDomain::User
326
-
327
- define_method :execute do
328
- SomeOrg::SomeDomain::User.thunk(some_other_user_id)
329
- end
330
- end
331
-
332
- command_connector.connect(SomeOrg::SomeDomain::FindUser)
333
- end
334
-
335
- it "returns a thunk but in the command connector's namespace" do
336
- expect(response.status).to be(0)
337
- expect(JSON.parse(response.body)).to eq(some_other_user.id)
338
- end
339
- end
340
-
341
- context "when nothing in the array needs to be changed" do
342
- let(:inputs) do
343
- {
344
- username: "foo",
345
- password: "bar",
346
- foo: [{ baz: "baz" }, { baz: "baz2" }]
347
- }
348
- end
349
-
350
- it "does not include sensitive output values in the result" do
351
- expect(response.status).to be(0)
352
- expect(JSON.parse(response.body)).to eq(
353
- "id" => 1,
354
- "username" => "foo",
355
- "foo" => [
356
- { "baz" => "baz" },
357
- { "baz" => "baz2" }
358
- ]
359
- )
360
- end
361
- end
362
-
363
- context "when nothing in the record needs to be changed" do
364
- let(:inputs) do
365
- {
366
- username: "foo",
367
- foo: []
368
- }
369
- end
370
-
371
- it "does not include sensitive output values in the result" do
372
- expect(response.status).to be(0)
373
- expect(JSON.parse(response.body)).to eq(
374
- "id" => 1,
375
- "username" => "foo",
376
- "foo" => []
377
- )
378
- end
379
- end
380
-
381
- context "when entity is a detached entity" do
382
- let(:full_command_name) { "BuildSomeDetachedEntity" }
383
- let(:inputs) do
384
- {
385
- id: 1,
386
- username: "foo",
387
- password: "bar",
388
- foo: [{ bar: "bar", baz: "baz" }, { baz: "baz2" }]
389
- }
390
- end
391
-
392
- before do
393
- stub_class "SomeDetachedEntity", Foobara::DetachedEntity do
394
- attributes do
395
- id :integer
396
- password :string, :allow_nil, :sensitive
397
- username :string, :required
398
- foo :array do
399
- bar :string, :sensitive, :allow_nil
400
- baz :string
401
- end
402
- end
403
-
404
- primary_key :id
405
- end
406
-
407
- stub_class "BuildSomeDetachedEntity", Foobara::Command do
408
- inputs do
409
- id :integer, :required
410
- username :string, :required
411
- password :string, :sensitive
412
- foo :array do
413
- bar :string, :sensitive, :allow_nil
414
- baz :string
415
- end
416
- end
417
-
418
- result SomeDetachedEntity
419
-
420
- def execute
421
- SomeDetachedEntity.new(inputs)
422
- end
423
- end
424
-
425
- command_connector.connect(BuildSomeDetachedEntity, serializers:, pre_commit_transformers:)
426
- end
427
-
428
- it "does not include sensitive output values in the result" do
429
- expect(response.status).to be(0)
430
- expect(JSON.parse(response.body)).to eq(
431
- "id" => 1,
432
- "username" => "foo",
433
- "foo" => [
434
- { "baz" => "baz" },
435
- { "baz" => "baz2" }
436
- ]
437
- )
438
- end
439
- end
440
- end
441
-
442
- describe "#all_exposed_command_names" do
443
- it "includes all of the exposed command names" do
444
- command_connector.connect(SomeOrg::SomeDomain::CreateUser)
445
- expect(command_connector.all_exposed_command_names).to eq(["SomeOrg::SomeDomain::CreateUser"])
446
- end
447
- end
448
-
449
- describe "#all_exposed_type_names" do
450
- it "includes the entity names" do
451
- command_connector.connect(SomeOrg::SomeDomain::CreateUser)
452
- expect(command_connector.all_exposed_type_names).to include("SomeOrg::SomeDomain::User")
453
- end
454
- end
455
- end
456
- end
457
-
458
- describe "#run_command" do
459
- before do
460
- if allowed_rules
461
- command_connector.allowed_rules(allowed_rules)
462
- end
463
-
464
- command_connector.connect(
465
- command_class,
466
- inputs: inputs_transformers_sugar,
467
- result: result_transformers_sugar,
468
- inputs_transformers:,
469
- result_transformers:,
470
- errors_transformers:,
471
- serializers:,
472
- response: response_mutators,
473
- request: request_mutators,
474
- allowed_rule:,
475
- requires_authentication:,
476
- pre_commit_transformers:,
477
- capture_unknown_error:,
478
- aggregate_entities:,
479
- atomic_entities:,
480
- suffix:
481
- )
482
- end
483
-
484
- let(:suffix) { nil }
485
-
486
- it "runs the command" do
487
- expect(response.status).to be(0)
488
- expect(response.body).to eq("8")
489
- end
490
-
491
- context "when requires_allowed_rule" do
492
- let(:command_connector) do
493
- described_class.new(
494
- authenticator:,
495
- default_serializers:,
496
- requires_allowed_rule: true
497
- )
498
- end
499
-
500
- it "gives a relevant error" do
501
- expect { response }.to raise_error(Foobara::CommandConnector::NoAllowedRuleGivenError)
502
- end
503
- end
504
-
505
- context "with default transformers" do
506
- before do
507
- identity = proc { |x| x }
508
-
509
- command_connector.add_default_inputs_transformer(identity)
510
- command_connector.add_default_result_transformer(identity)
511
- command_connector.add_default_errors_transformer(identity)
512
- command_connector.add_default_pre_commit_transformer(identity)
513
- end
514
-
515
- it "runs the command" do
516
- expect(response.status).to be(0)
517
- expect(response.body).to eq("8")
518
- end
519
- end
520
-
521
- context "without serializers" do
522
- let(:default_serializers) { nil }
523
- # Setting a suffix guarantees it will be transformed
524
- let(:suffix) { "Whatever" }
525
- let(:full_command_name) { "ComputeExponentWhatever" }
526
-
527
- it "runs the command" do
528
- expect(response.status).to be(0)
529
- expect(response.body).to eq(8)
530
- end
531
- end
532
-
533
- context "when inputs are bad" do
534
- let(:inputs) { { some_bad_input: 10, exponent: } }
535
-
536
- let(:default_serializers) { Foobara::CommandConnectors::Serializers::JsonSerializer }
537
- let(:serializers) { Foobara::CommandConnectors::Serializers::ErrorsSerializer }
538
-
539
- it "fails" do
540
- expect(response.status).to be(1)
541
-
542
- error = JSON.parse(response.body).find { |e| e["key"] == "data.unexpected_attributes" }
543
- unexpected_attributes = error["context"]["unexpected_attributes"]
544
-
545
- expect(unexpected_attributes).to eq(["some_bad_input"])
546
- end
547
- end
548
-
549
- context "when command doesn't exist" do
550
- let(:full_command_name) { "DoesNotExist" }
551
-
552
- it "raises" do
553
- expect {
554
- response
555
- }.to raise_error(Foobara::CommandConnector::NoCommandFoundError)
556
- end
557
- end
558
-
559
- context "when unknown error" do
560
- let(:capture_unknown_error) { true }
561
- let(:default_serializers) do
562
- [
563
- Foobara::CommandConnectors::Serializers::ErrorsSerializer,
564
- Foobara::CommandConnectors::Serializers::JsonSerializer
565
- ]
566
- end
567
-
568
- before do
569
- command_class.define_method :execute do
570
- raise "kaboom!"
571
- end
572
- end
573
-
574
- it "fails" do
575
- expect(response.status).to be(1)
576
-
577
- error = JSON.parse(response.body).find { |e| e["key"] == "runtime.unknown" }
578
-
579
- expect(error["message"]).to eq("kaboom!")
580
- expect(error["is_fatal"]).to be(true)
581
- end
582
-
583
- context "when not capturing unknown errors when connecting the command" do
584
- let(:capture_unknown_error) { false }
585
-
586
- it "explodes" do
587
- expect { response }.to raise_error("kaboom!")
588
- end
589
-
590
- context "when capturing all unknown errors" do
591
- let(:command_connector) do
592
- described_class.new(authenticator:, default_serializers:, capture_unknown_error: true)
593
- end
594
-
595
- it "fails" do
596
- expect(response.status).to be(1)
597
-
598
- error = JSON.parse(response.body).find { |e| e["key"] == "runtime.unknown" }
599
-
600
- expect(error["message"]).to eq("kaboom!")
601
- expect(error["is_fatal"]).to be(true)
602
- end
603
- end
604
- end
605
- end
606
-
607
- context "with a response mutator" do
608
- let(:full_command_name) { "SomeCommand" }
609
- let(:response_mutators) { [response_mutator] }
610
- let(:response_mutator) { response_mutator_class }
611
-
612
- let(:command_class) do
613
- stub_class(:SomeCommand, Foobara::Command) do
614
- inputs value: :string
615
- result foo: :string, bar: :string
616
-
617
- def execute
618
- { foo: "foo #{value}", bar: "bar #{value}" }
619
- end
620
- end
621
- end
622
-
623
- let(:inputs) { { value: "some value" } }
624
-
625
- let(:response_mutator_class) do
626
- stub_class("ChangeBarToBazMutator", Foobara::CommandConnectors::ResponseMutator) do
627
- def result_type_declaration_from(result_type)
628
- new_declaration = Foobara::Util.deep_dup(result_type.declaration_data)
629
- element_type_declarations = new_declaration[:element_type_declarations]
630
-
631
- old_bar = element_type_declarations.delete(:bar)
632
-
633
- element_type_declarations[:baz] = old_bar
634
-
635
- new_declaration
636
- end
637
-
638
- def mutate(response)
639
- bar = response.body.delete(:bar)
640
- response.body[:baz] = bar
641
- end
642
- end
643
- end
644
-
645
- it "mutates the response and gives an expected mutated result type in the manifest" do
646
- manifest = command_connector.foobara_manifest
647
-
648
- expect(manifest[:command][:SomeCommand][:response_mutators]).to eq(["ChangeBarToBazMutator"])
649
-
650
- expect(manifest[:command][:SomeCommand][:result_type]).to eq(
651
- type: :attributes,
652
- element_type_declarations: {
653
- baz: :string,
654
- foo: :string
655
- }
656
- )
657
- expect(JSON.parse(response.body)).to eq("foo" => "foo some value", "baz" => "bar some value")
658
- end
659
-
660
- describe "#foobara_manifest" do
661
- context "when mutator is an instance" do
662
- let(:response_mutator) { response_mutator_class.new(true) }
663
-
664
- it "mutates the response and gives an expected mutated result type in the manifest" do
665
- manifest = command_connector.foobara_manifest
666
- expect(manifest[:command][:SomeCommand][:response_mutators]).to eq(["ChangeBarToBazMutator"])
667
- end
668
-
669
- context "when mutator is an anonymous instance" do
670
- let(:response_mutator_class) do
671
- Class.new(Foobara::CommandConnectors::ResponseMutator) do
672
- def result_type_declaration_from(result_type)
673
- result_type
674
- end
675
- end
676
- end
677
-
678
- it "mutates the response and gives an expected mutated result type in the manifest" do
679
- manifest = command_connector.foobara_manifest
680
- expect(manifest[:command][:SomeCommand][:response_mutators].first).to be_a(String)
681
- end
682
- end
683
- end
684
- end
685
-
686
- context "with two mutators" do
687
- let(:response_mutators) { [response_mutator_class, another_mutator] }
688
-
689
- let(:another_mutator) do
690
- stub_class("RemoveFooMutator", Foobara::CommandConnectors::ResponseMutator) do
691
- def result_type_declaration_from(result_type)
692
- Foobara::TypeDeclarations::Attributes.reject(result_type.declaration_data, :foo)
693
- end
694
-
695
- def mutate(response)
696
- response.body.delete(:foo)
697
- end
698
- end
699
- end
700
-
701
- it "mutates the response and gives an expected mutated result type in the manifest" do
702
- manifest = command_connector.foobara_manifest
703
-
704
- expect(manifest[:command][:SomeCommand][:result_type]).to eq(
705
- type: :attributes,
706
- element_type_declarations: {
707
- baz: :string
708
- }
709
- )
710
- expect(JSON.parse(response.body)).to eq("baz" => "bar some value")
711
- end
712
- end
713
- end
714
-
715
- context "with a request mutator" do
716
- let(:full_command_name) { "SomeCommand" }
717
- let(:request_mutators) { [request_mutator_class] }
718
-
719
- let(:command_class) do
720
- stub_class(:SomeCommand, Foobara::Command) do
721
- inputs foo: :string, baz: :string
722
- result :duck
723
-
724
- def execute
725
- inputs
726
- end
727
- end
728
- end
729
-
730
- let(:inputs) { { foo: "foo some value", bar: "bar some value" } }
731
-
732
- let(:request_mutator_class) do
733
- stub_class("ChangeBarToBazMutator", Foobara::CommandConnectors::RequestMutator) do
734
- def inputs_type_declaration_from(inputs_type)
735
- new_declaration = Foobara::Util.deep_dup(inputs_type.declaration_data)
736
- element_type_declarations = new_declaration[:element_type_declarations]
737
-
738
- old_bar = element_type_declarations.delete(:baz)
739
-
740
- element_type_declarations[:bar] = old_bar
741
-
742
- new_declaration
743
- end
744
-
745
- def mutate(request)
746
- inputs = Foobara::Util.deep_dup(request.inputs)
747
- bar = inputs.delete(:bar)
748
- request.inputs = inputs.merge(baz: bar)
749
- end
750
- end
751
- end
752
-
753
- it "mutates the response and gives an expected mutated inputs type in the manifest" do
754
- manifest = command_connector.foobara_manifest
755
-
756
- expect(manifest[:command][:SomeCommand][:inputs_type]).to eq(
757
- type: :attributes,
758
- element_type_declarations: {
759
- bar: :string,
760
- foo: :string
761
- }
762
- )
763
-
764
- expect(JSON.parse(response.body)).to eq("foo" => "foo some value", "baz" => "bar some value")
765
- end
766
-
767
- context "with two mutators" do
768
- let(:request_mutators) { [request_mutator_class, another_mutator] }
769
-
770
- let(:another_mutator) do
771
- stub_class("RemoveFoo2Mutator", Foobara::CommandConnectors::RequestMutator) do
772
- def inputs_type_declaration_from(inputs_type)
773
- with_foo2 = Foobara::Domain.current.foobara_type_from_declaration(foo2: :integer)
774
- Foobara::TypeDeclarations::Attributes.merge(inputs_type.declaration_data, with_foo2.declaration_data)
775
- end
776
-
777
- def mutate(response)
778
- inputs = response.inputs.dup
779
- inputs.delete(:foo2)
780
- response.inputs = inputs
781
- end
782
- end
783
- end
784
-
785
- it "mutates the request and gives an expected mutated inputs type in the manifest" do
786
- manifest = Foobara::TypeDeclarations.with_manifest_context(include_processors: true) do
787
- command_connector.foobara_manifest
788
- end
789
-
790
- expect(manifest[:command][:SomeCommand][:inputs_type]).to eq(
791
- type: :attributes,
792
- element_type_declarations: {
793
- foo2: :integer,
794
- foo: :string,
795
- bar: :string
796
- }
797
- )
798
-
799
- expect(JSON.parse(response.body)).to eq("baz" => "bar some value", "foo" => "foo some value")
800
- end
801
- end
802
- end
803
-
804
- context "with various transformers" do
805
- let(:inputs) { { bbaassee: base, exponent: } }
806
-
807
- let(:inputs_transformers) { [inputs_transformer] }
808
- let(:inputs_transformer) do
809
- stub_class(:RandomTransformer, Foobara::Value::Transformer) do
810
- def transform(inputs)
811
- {
812
- base: inputs[:bbaassee],
813
- exponent: inputs[:exponent]
814
- }
815
- end
816
- end
817
- end
818
-
819
- let(:result_transformers) { [->(result) { result * 2 }] }
820
- let(:errors_transformers) { [->(errors) { errors }] }
821
-
822
- it "runs the command" do
823
- expect(response.status).to be(0)
824
- expect(response.body).to eq("16")
825
- end
826
-
827
- context "when error" do
828
- let(:inputs) { { foo: "bar", exponent: } }
829
-
830
- it "is not success" do
831
- expect(response.status).to be(1)
832
- expect(response.body).to include("cannot_cast")
833
- end
834
- end
835
-
836
- context "with multiple transformers" do
837
- let(:identity) { ->(x) { x } }
838
-
839
- let(:inputs_transformers) { [inputs_transformer] }
840
- let(:inputs_transformers_sugar) { identity }
841
- let(:result_transformers) { [->(result) { result * 2 }, identity] }
842
- let(:errors_transformers) { [identity, identity] }
843
- let(:pre_commit_transformers) { [identity, identity] }
844
-
845
- it "runs the command and has the expected inputs type" do
846
- expect(response.status).to be(0)
847
- expect(response.body).to eq("16")
848
-
849
- transformed_command = command_connector.transformed_command_from_name("ComputeExponent")
850
- expect(transformed_command.inputs_type.declaration_data).to eq(
851
- type: :attributes,
852
- element_type_declarations: {
853
- base: :integer,
854
- exponent: :integer
855
- }
856
- )
857
- end
858
-
859
- context "with a typed transformer" do
860
- let(:identity) do
861
- stub_class "IdentityTransformer", Foobara::TypeDeclarations::TypedTransformer do
862
- def from_type_declaration
863
- to_type
864
- end
865
-
866
- def transform(value)
867
- value
868
- end
869
- end
870
- end
871
-
872
- it "runs the command and has the expected inputs type" do
873
- expect(response.status).to be(0)
874
- expect(response.body).to eq("16")
875
-
876
- transformed_command = command_connector.transformed_command_from_name("ComputeExponent")
877
- expect(transformed_command.inputs_type.declaration_data).to eq(
878
- type: :attributes,
879
- element_type_declarations: {
880
- base: :integer,
881
- exponent: :integer
882
- }
883
- )
884
- end
885
- end
886
-
887
- context "when error" do
888
- let(:inputs) { { foo: "bar", exponent: } }
889
-
890
- it "is not success" do
891
- expect(response.status).to be(1)
892
- expect(response.body).to include("cannot_cast")
893
- end
894
- end
895
- end
896
-
897
- context "with transformer instance instead of class" do
898
- let(:inputs_transformers) { [inputs_transformer.instance] }
899
-
900
- it "runs the command" do
901
- expect(response.status).to be(0)
902
- expect(response.body).to eq("16")
903
- end
904
- end
905
- end
906
-
907
- context "with allowed rule" do
908
- context "when declared with a hash" do
909
- let(:allowed_rule) do
910
- logic = proc {
911
- raise unless respond_to?(:base)
912
-
913
- base == 2
914
- }
915
-
916
- {
917
- logic:,
918
- symbol: :must_be_base_2
919
- }
920
- end
921
-
922
- context "when allowed" do
923
- it "runs the command" do
924
- expect(response.status).to be(0)
925
- expect(response.body).to eq("8")
926
- end
927
- end
928
-
929
- context "when not allowed" do
930
- let(:allowed_rule) do
931
- logic = proc { base == 1900 }
932
-
933
- {
934
- logic:,
935
- symbol: :must_be_base_1900,
936
- explanation: proc { "Must be 1900 but was #{base}" }
937
- }
938
- end
939
-
940
- it "fails with 403 and relevant error" do
941
- expect(response.status).to be(1)
942
- expect(JSON.parse(response.body).find { |e|
943
- e["key"] == "runtime.not_allowed"
944
- }["message"]).to eq(
945
- "Not allowed: Must be 1900 but was 2"
946
- )
947
- end
948
- end
949
- end
950
-
951
- context "when declared with the rule registry" do
952
- let(:allowed_rules) do
953
- {
954
- must_be_base_2: {
955
- logic: proc { base == 2 },
956
- explanation: "Must be base 2"
957
- },
958
- must_be_base_1900: {
959
- logic: proc { base == 1900 },
960
- explanation: proc { "Must be base 1900 but was #{base}" }
961
- }
962
- }
963
- end
964
-
965
- context "when allowed" do
966
- let(:allowed_rule) { [:must_be_base_1900, "must_be_base_2"] }
967
-
968
- it "runs the command" do
969
- expect(response.status).to be(0)
970
- expect(response.body).to eq("8")
971
- end
972
-
973
- describe "#manifest" do
974
- it "contains the errors for not allowed" do
975
- error_manifest = command_connector.foobara_manifest[:command][:ComputeExponent][:possible_errors]
976
-
977
- expect(error_manifest.keys).to include("runtime.not_allowed")
978
- end
979
- end
980
- end
981
-
982
- context "when not allowed" do
983
- let(:allowed_rule) do
984
- :must_be_base_1900
985
- end
986
-
987
- it "fails with 401 and relevant error" do
988
- expect(command_connector.command_registry[ComputeExponent].command_class).to eq(ComputeExponent)
989
-
990
- expect(response.status).to be(1)
991
- expect(JSON.parse(response.body).find { |e|
992
- e["key"] == "runtime.not_allowed"
993
- }["message"]).to eq(
994
- "Not allowed: Must be base 1900 but was 2"
995
- )
996
- end
997
- end
998
- end
999
-
1000
- context "when declared with a proc" do
1001
- context "without explanation" do
1002
- let(:allowed_rule) do
1003
- proc { base == 1900 }
1004
- end
1005
- let(:authenticator) do
1006
- # normally we would return a user but we'll just use junk
1007
- proc { Object.new }
1008
- end
1009
-
1010
- it "fails with 401 and relevant error" do
1011
- expect(response.status).to be(1)
1012
- expect(response.outcome).to_not be_success
1013
- expect(
1014
- JSON.parse(response.body).find { |e| e["key"] == "runtime.not_allowed" }["message"]
1015
- ).to match(/not.?allowed/i)
1016
- end
1017
-
1018
- describe "#foobara_manifest" do
1019
- it "contains info about the authenticator" do
1020
- manifest = command_connector.foobara_manifest
1021
- expect(manifest[:command][:ComputeExponent][:authenticator]).to eq(
1022
- symbol: :authenticator,
1023
- explanation: :authenticator
1024
- )
1025
- end
1026
- end
1027
- end
1028
- end
1029
-
1030
- context "when authentication required" do
1031
- let(:requires_authentication) { true }
1032
- let(:authenticator) do
1033
- proc {}
1034
- end
1035
-
1036
- describe "#manifest" do
1037
- it "contains the errors for not allowed" do
1038
- error_manifest = command_connector.foobara_manifest[:command][:ComputeExponent][:possible_errors]
1039
-
1040
- expect(error_manifest.keys).to include("runtime.unauthenticated")
1041
- end
1042
- end
1043
-
1044
- context "when unauthenticated" do
1045
- it "is 1" do
1046
- expect(response.status).to be(1)
1047
- expect(JSON.parse(response.body).map { |e| e["key"] }).to include("runtime.unauthenticated")
1048
- end
1049
- end
1050
-
1051
- context "when authenticated" do
1052
- let(:authenticator) do
1053
- # normally we would return a user but we'll just generate a pointless integer
1054
- # to test proxying to the request
1055
- proc { full_command_name.length }
1056
- end
1057
-
1058
- let(:default_serializers) do
1059
- [Foobara::CommandConnectors::Serializers::JsonSerializer]
1060
- end
1061
-
1062
- it "is 200" do
1063
- expect(response.status).to be(0)
1064
- expect(JSON.parse(response.body)).to eq(8)
1065
- end
1066
- end
1067
- end
1068
-
1069
- context "with an entity input" do
1070
- before do
1071
- Foobara::Persistence.default_crud_driver = Foobara::Persistence::CrudDrivers::InMemory.new
1072
- end
1073
-
1074
- let(:default_pre_commit_transformers) do
1075
- [
1076
- Foobara::CommandConnectors::Transformers::LoadAtomsPreCommitTransformer
1077
- ]
1078
- end
1079
-
1080
- let(:command_class) do
1081
- user_class
1082
-
1083
- stub_class(:QueryUser, Foobara::Command) do
1084
- inputs user: User
1085
- result :User
1086
-
1087
- load_all
1088
-
1089
- def execute
1090
- user
1091
- end
1092
- end
1093
- end
1094
-
1095
- let(:full_command_name) { "QueryUser" }
1096
- let(:inputs) { { user: user_id } }
1097
-
1098
- let(:user_class) do
1099
- stub_class(:User, Foobara::Entity) do
1100
- attributes id: :integer,
1101
- name: :string,
1102
- ratings: [:integer],
1103
- junk: { type: :associative_array, value_type_declaration: :array }
1104
- primary_key :id
1105
- end
1106
- end
1107
-
1108
- context "when user exists" do
1109
- let(:user_id) do
1110
- User.transaction do
1111
- User.create(name: :whatever)
1112
- end.id
1113
- end
1114
-
1115
- let(:result_transformers) { [proc(&:attributes)] }
1116
-
1117
- it "finds the user" do
1118
- expect(response.status).to be(0)
1119
- expect(JSON.parse(response.body)).to eq("id" => user_id, "name" => "whatever")
1120
- end
1121
- end
1122
-
1123
- context "when not found error" do
1124
- let(:user_id) { 100 }
1125
-
1126
- it "fails" do
1127
- expect(response.status).to be(1)
1128
-
1129
- errors = JSON.parse(response.body)
1130
-
1131
- expect(errors.size).to eq(1)
1132
- expect(errors.map { |e| e["key"] }).to include("runtime.user_not_found")
1133
- end
1134
- end
1135
-
1136
- context "with an association" do
1137
- let(:point_class) do
1138
- stub_class :Point, Foobara::Model do
1139
- attributes x: :integer, y: :integer
1140
- end
1141
- end
1142
-
1143
- let(:referral_class) do
1144
- stub_class(:Referral, Foobara::Entity) do
1145
- attributes id: :integer, email: :email
1146
- primary_key :id
1147
- end
1148
- end
1149
-
1150
- before do
1151
- User.attributes referral: referral_class, point: point_class
1152
- end
1153
-
1154
- context "with atomic_entities: true" do
1155
- let(:atomic_entities) { true }
1156
-
1157
- it "includes the AtomicSerializer" do
1158
- command_manifest = command_connector.foobara_manifest[:command][:QueryUser]
1159
- expect(
1160
- command_manifest[:serializers]
1161
- ).to include("Foobara::CommandConnectors::Serializers::AtomicSerializer")
1162
- end
1163
- end
1164
-
1165
- context "with AtomicSerializer" do
1166
- let(:serializers) { Foobara::CommandConnectors::Serializers::AtomicSerializer }
1167
-
1168
- context "when user exists with a referral" do
1169
- let(:user) do
1170
- User.transaction do
1171
- referral = referral_class.create(email: "Some@email.com")
1172
- User.create(name: "Some Name", referral:, ratings: [1, 2, 3], point: { x: 1, y: 2 })
1173
- end
1174
- end
1175
-
1176
- let(:user_id) { user.id }
1177
-
1178
- let(:referral_id) { user.referral.id }
1179
-
1180
- it "serializes as an atom" do
1181
- expect(response.status).to be(0)
1182
- expect(JSON.parse(response.body)).to eq(
1183
- "id" => user_id,
1184
- "name" => "Some Name",
1185
- "referral" => referral_id,
1186
- "ratings" => [1, 2, 3],
1187
- "point" => { "x" => 1, "y" => 2 }
1188
- )
1189
- end
1190
- end
1191
- end
1192
-
1193
- context "with AggregateSerializer" do
1194
- let(:serializers) { Foobara::CommandConnectors::Serializers::AggregateSerializer }
1195
- let(:pre_commit_transformers) {
1196
- Foobara::CommandConnectors::Transformers::LoadAggregatesPreCommitTransformer
1197
- }
1198
-
1199
- context "when user exists with a referral" do
1200
- let(:command_class) do
1201
- user_class
1202
- referral_class
1203
-
1204
- stub_class :QueryUser, Foobara::Command do
1205
- inputs user: User
1206
- result stuff: [User, Referral]
1207
-
1208
- load_all
1209
-
1210
- def execute
1211
- {
1212
- stuff: [user, user.referral]
1213
- }
1214
- end
1215
- end
1216
- end
1217
-
1218
- let(:user) do
1219
- User.transaction do
1220
- referral = referral_class.create(email: "Some@email.com")
1221
- User.create(
1222
- name: "Some Name",
1223
- referral:,
1224
- ratings: [1, 2, 3],
1225
- point: { x: 1, y: 2 },
1226
- junk: { [1, 2, 3] => [1, 2, 3] }
1227
- )
1228
- end
1229
- end
1230
-
1231
- let(:user_id) { user.id }
1232
- let(:referral_id) { user.referral.id }
1233
-
1234
- it "serializes as an aggregate" do
1235
- expect(response.status).to be(0)
1236
- expect(JSON.parse(response.body)).to eq(
1237
- "stuff" => [
1238
- {
1239
- "id" => 1,
1240
- # TODO: This is kind of crazy that we can only have strings as keys. Should raise exception.
1241
- "junk" => { "[1, 2, 3]" => [1, 2, 3] },
1242
- "name" => "Some Name",
1243
- "point" => { "x" => 1, "y" => 2 },
1244
- "ratings" => [1, 2, 3],
1245
- "referral" => { "email" => "some@email.com", "id" => 1 }
1246
- },
1247
- {
1248
- "email" => "some@email.com", "id" => 1
1249
- }
1250
- ]
1251
- )
1252
- end
1253
-
1254
- it "contains pre_commit_transformers in its manifest" do
1255
- command_manifest = Foobara::TypeDeclarations.with_manifest_context(include_processor: true) do
1256
- command_connector.foobara_manifest[:command][:QueryUser]
1257
- end
1258
- expect(command_manifest[:pre_commit_transformers]).to include(
1259
- "Foobara::CommandConnectors::Transformers::LoadAggregatesPreCommitTransformer"
1260
- )
1261
- expect(command_manifest[:serializers]).to include(
1262
- "Foobara::CommandConnectors::Serializers::AggregateSerializer"
1263
- )
1264
- end
1265
-
1266
- context "with aggregate serializer as default serializer" do
1267
- let(:aggregate_entities) { nil }
1268
- let(:pre_commit_transformers) { nil }
1269
- let(:serializers) { nil }
1270
-
1271
- let(:default_serializers) do
1272
- [
1273
- Foobara::CommandConnectors::Serializers::AggregateSerializer,
1274
- Foobara::CommandConnectors::Serializers::ErrorsSerializer,
1275
- Foobara::CommandConnectors::Serializers::JsonSerializer
1276
- ]
1277
- end
1278
-
1279
- let(:default_pre_commit_transformers) do
1280
- Foobara::CommandConnectors::Transformers::LoadAggregatesPreCommitTransformer
1281
- end
1282
-
1283
- it "contains pre_commit_transformers in its manifest" do
1284
- command_manifest = command_connector.foobara_manifest[:command][:QueryUser]
1285
- expect(command_manifest[:pre_commit_transformers]).to include(
1286
- "Foobara::CommandConnectors::Transformers::LoadAggregatesPreCommitTransformer"
1287
- )
1288
- expect(command_manifest[:serializers]).to include(
1289
- "Foobara::CommandConnectors::Serializers::AggregateSerializer"
1290
- )
1291
- end
1292
-
1293
- context "when disabled via aggregate_entities: false" do
1294
- let(:aggregate_entities) { false }
1295
-
1296
- it "does not contain pre_commit_transformers in its manifest" do
1297
- command_manifest = command_connector.foobara_manifest[:command][:QueryUser]
1298
- expect(command_manifest[:pre_commit_transformers]).to be_nil
1299
-
1300
- expect(
1301
- command_manifest[:serializers]
1302
- ).to_not include("CommandConnectors::Serializers::AggregateSerializer")
1303
- end
1304
- end
1305
- end
1306
- end
1307
- end
1308
-
1309
- context "with RecordStoreSerializer" do
1310
- let(:serializers) { Foobara::CommandConnectors::Serializers::RecordStoreSerializer }
1311
- let(:aggregate_entities) { true }
1312
-
1313
- context "when user exists with a referral" do
1314
- let(:user) do
1315
- User.transaction do
1316
- referral = referral_class.create(email: "Some@email.com")
1317
- User.create(name: "Some Name", referral:, ratings: [1, 2, 3], point: { x: 1, y: 2 })
1318
- end
1319
- end
1320
-
1321
- let(:user_id) { user.id }
1322
-
1323
- let(:referral_id) { user.referral.id }
1324
-
1325
- it "serializes as a record store" do
1326
- expect(response.status).to be(0)
1327
- expect(JSON.parse(response.body)).to eq(
1328
- "User" => {
1329
- "1" => {
1330
- "id" => 1,
1331
- "name" => "Some Name",
1332
- "referral" => 1,
1333
- "ratings" => [1, 2, 3],
1334
- "point" => { "x" => 1, "y" => 2 }
1335
- }
1336
- },
1337
- "Referral" => {
1338
- "1" => {
1339
- "id" => 1,
1340
- "email" => "some@email.com"
1341
- }
1342
- }
1343
- )
1344
- end
1345
- end
1346
- end
1347
- end
1348
- end
1349
-
1350
- describe "#manifest" do
1351
- context "when various transformers" do
1352
- let(:inputs) { { bbaassee: base, exponent: } }
1353
-
1354
- let(:inputs_transformers) { [inputs_transformer] }
1355
- let(:inputs_transformer) do
1356
- stub_class "SomeTransformer", Foobara::TypeDeclarations::TypedTransformer do
1357
- def from_type_declaration
1358
- {
1359
- bbaassee: :string,
1360
- exponent: :string
1361
- }
1362
- end
1363
-
1364
- def transform(inputs)
1365
- {
1366
- base: inputs[:bbaassee],
1367
- exponent: inputs[:exponent]
1368
- }
1369
- end
1370
- end
1371
- end
1372
-
1373
- let(:result_transformers) { [result_transformer] }
1374
- let(:result_transformer) do
1375
- stub_class :SomeOtherTransformer, Foobara::TypeDeclarations::TypedTransformer do
1376
- to(answer: :string)
1377
-
1378
- def transform(result)
1379
- { answer: result.to_s }
1380
- end
1381
- end
1382
- end
1383
-
1384
- it "runs the command" do
1385
- expect(response.status).to be(0)
1386
- expect(response.command.raw_inputs).to eq(bbaassee: 2, exponent: 3)
1387
- expect(JSON.parse(response.body)).to eq("answer" => "8")
1388
- end
1389
-
1390
- context "with bad inputs" do
1391
- let(:inputs_transformer) do
1392
- stub_class "SomeTransformer", Foobara::TypeDeclarations::TypedTransformer do
1393
- def from_type_declaration
1394
- Foobara::Domain.current.foobara_type_from_declaration do
1395
- bbaassee :string, :required
1396
- exponent :string, :required
1397
- end
1398
- end
1399
- end
1400
- end
1401
-
1402
- let(:inputs) { { exponent: } }
1403
-
1404
- it "is not success" do
1405
- expect(response.status).to be(1)
1406
- end
1407
- end
1408
-
1409
- describe "#manifest" do
1410
- let(:manifest) do
1411
- Foobara::TypeDeclarations.with_manifest_context(include_processors: true) do
1412
- command_connector.foobara_manifest
1413
- end
1414
- end
1415
-
1416
- it "uses types from the transformers" do
1417
- h = manifest[:command][:ComputeExponent]
1418
-
1419
- inputs_type = h[:inputs_type]
1420
- result_type = h[:result_type]
1421
- error_types = h[:possible_errors]
1422
-
1423
- expect(inputs_type).to eq(
1424
- type: :attributes,
1425
- element_type_declarations: {
1426
- exponent: :string,
1427
- bbaassee: :string
1428
- }
1429
- )
1430
- expect(result_type).to eq(
1431
- type: :attributes,
1432
- element_type_declarations: {
1433
- answer: :string
1434
- }
1435
- )
1436
- expect(error_types).to eq(
1437
- "runtime.some_runtime" => {
1438
- category: :runtime,
1439
- symbol: :some_runtime,
1440
- key: "runtime.some_runtime",
1441
- error: "SomeRuntimeError"
1442
- },
1443
- "data.base.some_input" => {
1444
- path: [:base],
1445
- category: :data,
1446
- symbol: :some_input,
1447
- key: "data.base.some_input",
1448
- error: "SomeInputError",
1449
- manually_added: true
1450
- },
1451
- "data.cannot_cast" => {
1452
- category: :data,
1453
- symbol: :cannot_cast,
1454
- key: "data.cannot_cast",
1455
- error: "Foobara::Value::Processor::Casting::CannotCastError",
1456
- processor_class: "Foobara::Value::Processor::Casting",
1457
- processor_manifest_data: {
1458
- casting: { cast_to: { type: :attributes,
1459
- element_type_declarations: {
1460
- bbaassee: :string, exponent: :string
1461
- } } }
1462
- }
1463
- },
1464
- "data.unexpected_attributes" => {
1465
- category: :data,
1466
- symbol: :unexpected_attributes,
1467
- key: "data.unexpected_attributes",
1468
- error: "attributes::SupportedProcessors::ElementTypeDeclarations::UnexpectedAttributesError",
1469
- processor_class: "attributes::SupportedProcessors::ElementTypeDeclarations",
1470
- processor_manifest_data: { element_type_declarations: { bbaassee: :string,
1471
- exponent: :string } }
1472
- },
1473
- "data.bbaassee.cannot_cast" => {
1474
- path: [:bbaassee],
1475
- category: :data,
1476
- symbol: :cannot_cast,
1477
- key: "data.bbaassee.cannot_cast",
1478
- error: "Foobara::Value::Processor::Casting::CannotCastError",
1479
- processor_manifest_data: { casting: { cast_to: :string } }
1480
- },
1481
- "data.exponent.cannot_cast" => {
1482
- path: [:exponent],
1483
- category: :data,
1484
- symbol: :cannot_cast,
1485
- key: "data.exponent.cannot_cast",
1486
- error: "Foobara::Value::Processor::Casting::CannotCastError",
1487
- processor_manifest_data: { casting: { cast_to: :string } }
1488
- }
1489
- )
1490
- end
1491
- end
1492
-
1493
- describe "#possible_errors" do
1494
- it "contains paths matching the transformed inputs" do
1495
- transformed_command = command_connector.transformed_command_from_name("ComputeExponent")
1496
- expect(transformed_command.possible_errors.map(&:key).map(&:to_s)).to contain_exactly(
1497
- "runtime.some_runtime",
1498
- "data.base.some_input",
1499
- "data.cannot_cast",
1500
- "data.unexpected_attributes",
1501
- "data.bbaassee.cannot_cast",
1502
- "data.exponent.cannot_cast"
1503
- )
1504
- end
1505
- end
1506
- end
1507
- end
1508
-
1509
- context "with describe path" do
1510
- let(:action) { "describe" }
1511
- let(:full_command_name) { "ComputeExponent" }
1512
- let(:inputs) { {} }
1513
-
1514
- it "describes the command" do
1515
- expect(response.status).to be(0)
1516
- json = JSON.parse(response.body)
1517
- expect(json["inputs_type"]["element_type_declarations"]["base"]).to eq("integer")
1518
- end
1519
-
1520
- context "with describe path" do
1521
- let(:action) { "describe_command" }
1522
- let(:full_command_name) { "ComputeExponent" }
1523
-
1524
- it "describes the command" do
1525
- expect(response.status).to be(0)
1526
- json = JSON.parse(response.body)
1527
- expect(json["inputs_type"]["element_type_declarations"]["base"]).to eq("integer")
1528
- end
1529
- end
1530
- end
1531
-
1532
- context "with help path" do
1533
- let(:org_module) do
1534
- stub_module :SomeOrg do
1535
- foobara_organization!
1536
- end
1537
- end
1538
- let(:action) { "help" }
1539
-
1540
- let(:domain_module) do
1541
- org_module
1542
- stub_module("SomeOrg::SomeDomain") do
1543
- foobara_domain!
1544
- end
1545
- end
1546
-
1547
- let(:another_command_class) do
1548
- domain_module
1549
- stub_module "SomeOtherOrg" do
1550
- foobara_organization!
1551
- end
1552
- stub_module "SomeOtherOrg::SomeOtherDomain" do
1553
- foobara_domain!
1554
- end
1555
- stub_class "SomeOtherOrg::SomeOtherDomain::SomeOtherCommand", Foobara::Command do
1556
- inputs email: :email
1557
- end
1558
- stub_class "SomeOrg::SomeDomain::SomeCommand", Foobara::Command do
1559
- description "just some command"
1560
- depends_on SomeOtherOrg::SomeOtherDomain::SomeOtherCommand
1561
- end
1562
- end
1563
-
1564
- before do
1565
- command_connector.connect(another_command_class)
1566
-
1567
- stub_class("Foobara::CommandConnector::Commands::Help", Foobara::Command) do
1568
- inputs request: Foobara::CommandConnector::Request
1569
- result :string
1570
-
1571
- def execute
1572
- "HELP!!!"
1573
- end
1574
- end
1575
- end
1576
-
1577
- it "gives some help" do
1578
- expect(response.status).to be(0)
1579
- expect(response.body).to match(/HELP!!!/)
1580
- end
1581
-
1582
- context "when asking for help with a specific element" do
1583
- let(:action) { "help" }
1584
- let(:full_command_name) { "ComputeExponent" }
1585
-
1586
- it "gives some help" do
1587
- expect(response.status).to be(0)
1588
- expect(response.body).to match(/HELP!!!/)
1589
- end
1590
- end
1591
-
1592
- context "when it is something accessible through GlobalOrganization but not the connector" do
1593
- before do
1594
- command_connector.connect(new_command)
1595
-
1596
- stub_class("Foobara::CommandConnector::Commands::Help", Foobara::Command) do
1597
- inputs request: Foobara::CommandConnector::Request
1598
- result :string
1599
-
1600
- def execute
1601
- "HELP!!!"
1602
- end
1603
- end
1604
- end
1605
-
1606
- let(:new_command) do
1607
- stub_class(:NewCommand, Foobara::Command) do
1608
- inputs do
1609
- count :integer, min: 0
1610
- log [:string]
1611
- end
1612
- end
1613
- end
1614
-
1615
- context "when command" do
1616
- let(:action) { "help" }
1617
- let(:full_command_name) { "NewCommand" }
1618
-
1619
- it "gives some help" do
1620
- expect(response.status).to be(0)
1621
- expect(response.body).to match("HELP!!!")
1622
- end
1623
- end
1624
- end
1625
- end
1626
-
1627
- context "when the command returns a model from a domain it depends on (bad form but let's support it for now)" do
1628
- let(:command_class) do
1629
- user_class
1630
-
1631
- stub_module("DomainA") do
1632
- foobara_domain!
1633
- end
1634
- stub_class("DomainA::MakeUser", Foobara::Command) do
1635
- result DomainB::User
1636
- end
1637
- end
1638
-
1639
- let(:full_command_name) { "DomainA::MakeUser" }
1640
-
1641
- let(:user_class) do
1642
- stub_module("DomainB") do
1643
- foobara_domain!
1644
- end
1645
-
1646
- stub_class("DomainB::User", Foobara::Model) do
1647
- attributes name: :string
1648
- end
1649
- end
1650
-
1651
- it "includes the model and its domain in the manifest" do
1652
- manifest = command_connector.foobara_manifest
1653
-
1654
- expect(manifest[:domain].keys).to include(:DomainB)
1655
- expect(manifest[:type].keys).to include(:"DomainB::User")
1656
- end
1657
- end
1658
-
1659
- context "when command returns a model that has sensitive attributes nested within it" do
1660
- before do
1661
- Foobara::Persistence.default_crud_driver = Foobara::Persistence::CrudDrivers::InMemory.new
1662
- end
1663
-
1664
- let(:default_serializers) do
1665
- [
1666
- Foobara::CommandConnectors::Serializers::AggregateSerializer,
1667
- Foobara::CommandConnectors::Serializers::ErrorsSerializer,
1668
- Foobara::CommandConnectors::Serializers::JsonSerializer
1669
- ]
1670
- end
1671
- # TODO: make this automatic if AggregateSerializer is being used
1672
- let(:pre_commit_transformers) { Foobara::CommandConnectors::Transformers::LoadAggregatesPreCommitTransformer }
1673
-
1674
- let(:command_class) do
1675
- user_class
1676
-
1677
- stub_class(:QueryUser, Foobara::Command) do
1678
- inputs user: User
1679
- result :User
1680
-
1681
- load_all
1682
-
1683
- def execute
1684
- user
1685
- end
1686
- end
1687
- end
1688
-
1689
- let(:full_command_name) { "QueryUser" }
1690
- let(:inputs) { { user: user_id } }
1691
-
1692
- let(:user_class) do
1693
- rating_class
1694
- stub_class(:User, Foobara::Entity) do
1695
- attributes do
1696
- id :integer
1697
- name :string
1698
- ssn :string, :sensitive
1699
- ratings [:Rating]
1700
- end
1701
-
1702
- primary_key :id
1703
- end
1704
- end
1705
-
1706
- let(:rating_class) do
1707
- stub_class(:Rating, Foobara::Entity) do
1708
- attributes do
1709
- id :integer
1710
- rating :integer
1711
- secret :string, :sensitive
1712
- end
1713
-
1714
- primary_key :id
1715
- end
1716
- end
1717
-
1718
- context "when user exists with a rating" do
1719
- let(:user_id) do
1720
- User.transaction do
1721
- User.create(name: :whatever, ssn: "ssn", ratings: [Rating.create(rating: 1, secret: "secret")])
1722
- end.id
1723
- end
1724
-
1725
- it "finds the user" do
1726
- expect(response.status).to be(0)
1727
- expect(JSON.parse(response.body)).to eq(
1728
- "id" => 1,
1729
- "name" => "whatever",
1730
- "ratings" => [{
1731
- "id" => 1,
1732
- "rating" => 1
1733
- }]
1734
- )
1735
- end
1736
- end
1737
- end
1738
-
1739
- context "when command returns an entity that has delegated attributes" do
1740
- before do
1741
- Foobara::Persistence.default_crud_driver = Foobara::Persistence::CrudDrivers::InMemory.new
1742
- end
1743
-
1744
- let(:default_serializers) do
1745
- [
1746
- Foobara::CommandConnectors::Serializers::ErrorsSerializer,
1747
- Foobara::CommandConnectors::Serializers::AtomicSerializer,
1748
- Foobara::CommandConnectors::Serializers::JsonSerializer
1749
- ]
1750
- end
1751
-
1752
- # TODO: make this a default based on a flag
1753
- let(:pre_commit_transformers) do
1754
- Foobara::CommandConnectors::Transformers::LoadDelegatedAttributesEntitiesPreCommitTransformer
1755
- end
1756
-
1757
- let(:command_class) do
1758
- user_class
1759
-
1760
- stub_class(:CreateUser, Foobara::Command) do
1761
- inputs User.attributes_for_create
1762
- result :User
1763
-
1764
- def execute
1765
- User.create(inputs)
1766
- end
1767
- end
1768
-
1769
- stub_class(:QueryUser, Foobara::Command) do
1770
- inputs do
1771
- stuff do
1772
- things :array do
1773
- auth_user AuthUser, :required
1774
- end
1775
- end
1776
- end
1777
-
1778
- result do
1779
- stuff2 do
1780
- things2 :array do
1781
- user User, :required
1782
- end
1783
- end
1784
- end
1785
-
1786
- load_all
1787
-
1788
- def execute
1789
- user = User.that_owns(stuff[:things][0][:auth_user])
1790
- { stuff2: { things2: [{ user: }] } }
1791
- end
1792
- end
1793
- end
1794
-
1795
- let(:full_command_name) { "QueryUser" }
1796
- let(:inputs) do
1797
- {
1798
- stuff: {
1799
- things: [{ auth_user: auth_user_id }]
1800
- }
1801
- }
1802
- end
1803
-
1804
- let(:user_class) do
1805
- auth_user_class
1806
- stub_class(:User, Foobara::Entity) do
1807
- attributes do
1808
- id :integer
1809
- name :string
1810
- ssn :string, :sensitive
1811
- ssn2 :string, :private
1812
- foo :string
1813
- stuff :private do
1814
- things :array do
1815
- auth_user AuthUser, :required
1816
- end
1817
- end
1818
- end
1819
-
1820
- primary_key :id
1821
- delegate_attribute :username, [:stuff, :things, :"0", :auth_user, :username]
1822
- end
1823
- end
1824
-
1825
- let(:auth_user_class) do
1826
- stub_class(:AuthUser, Foobara::Entity) do
1827
- attributes do
1828
- id :integer
1829
- username :string
1830
- end
1831
-
1832
- primary_key :id
1833
- end
1834
- end
1835
-
1836
- context "when user exists" do
1837
- let(:user_id) do
1838
- CreateUser.run!(
1839
- name: :whatever,
1840
- ssn: "123",
1841
- ssn2: "789",
1842
- foo: "bar",
1843
- stuff: {
1844
- things: [
1845
- { auth_user: auth_user_id }
1846
- ]
1847
- }
1848
- ).id
1849
- end
1850
-
1851
- let(:username) { "some_username" }
1852
- let(:auth_user_id) do
1853
- AuthUser.transaction do
1854
- AuthUser.create(username:)
1855
- end.id
1856
- end
1857
-
1858
- before do
1859
- user_id
1860
- end
1861
-
1862
- it "finds the user and includes delegated attributes" do
1863
- expect(response.status).to be(0)
1864
- expect(JSON.parse(response.body)).to eq(
1865
- "stuff2" => {
1866
- "things2" => [
1867
- { "user" => {
1868
- "id" => user_id,
1869
- "name" => "whatever",
1870
- "foo" => "bar",
1871
- "username" => "some_username"
1872
- } }
1873
- ]
1874
- }
1875
- )
1876
- end
1877
-
1878
- context "with a simple entity return type" do
1879
- let(:command_class) do
1880
- user_class
1881
-
1882
- stub_class(:CreateUser, Foobara::Command) do
1883
- inputs User.attributes_for_create
1884
- result :User
1885
-
1886
- def execute
1887
- User.create(inputs)
1888
- end
1889
- end
1890
-
1891
- stub_class(:QueryUser, Foobara::Command) do
1892
- inputs do
1893
- stuff do
1894
- things :array do
1895
- auth_user AuthUser, :required
1896
- end
1897
- end
1898
- end
1899
-
1900
- result User
1901
-
1902
- load_all
1903
-
1904
- def execute
1905
- User.that_owns(stuff[:things][0][:auth_user])
1906
- end
1907
- end
1908
- end
1909
-
1910
- it "responds with attributes that include the delegated attributes" do
1911
- expect(response.status).to be(0)
1912
- expect(JSON.parse(response.body)).to eq(
1913
- "id" => 1,
1914
- "name" => "whatever",
1915
- "username" => "some_username",
1916
- "foo" => "bar"
1917
- )
1918
- end
1919
- end
1920
- end
1921
- end
1922
-
1923
- describe "connector manifest" do
1924
- describe "#manifest" do
1925
- let(:manifest) { command_connector.foobara_manifest }
1926
-
1927
- it "returns metadata about the commands" do
1928
- expect(
1929
- manifest[:command][:ComputeExponent][:result_type]
1930
- ).to eq(:integer)
1931
- end
1932
-
1933
- context "with an entity input" do
1934
- before do
1935
- Foobara::Persistence.default_crud_driver = Foobara::Persistence::CrudDrivers::InMemory.new
1936
- end
1937
-
1938
- after do
1939
- Foobara.reset_alls
1940
- end
1941
-
1942
- let(:command_class) do
1943
- user_class
1944
-
1945
- stub_class :QueryUser, Foobara::Command do
1946
- description "Queries a user"
1947
- inputs user: User.entity_type
1948
- result :User
1949
- end
1950
- end
1951
-
1952
- let(:full_command_name) { "QueryUser" }
1953
- let(:inputs) { { user: user_id } }
1954
-
1955
- let(:serializers) {
1956
- [proc(&:attributes)]
1957
- }
1958
-
1959
- let(:user_class) do
1960
- stub_class :User, Foobara::Entity do
1961
- attributes id: :integer, name: :string
1962
- primary_key :id
1963
- end
1964
- end
1965
-
1966
- it "returns metadata about the types referenced in the commands" do
1967
- expect(
1968
- manifest[:type].keys
1969
- ).to contain_exactly(:User, :array, :associative_array, :atomic_duck, :attributes, :detached_entity,
1970
- :duck, :duckture, :entity, :integer, :model, :number, :string, :symbol)
1971
- end
1972
-
1973
- context "with manifest path" do
1974
- let(:inputs) { {} }
1975
- let(:action) { "manifest" }
1976
-
1977
- it "includes types" do
1978
- expect(response.status).to be(0)
1979
- json = JSON.parse(response.body)
1980
- expect(json["type"].keys).to include("User")
1981
- end
1982
- end
1983
-
1984
- context "with list path" do
1985
- let(:inputs) { {} }
1986
- let(:action) { "list" }
1987
-
1988
- it "lists commands" do
1989
- expect(response.status).to be(0)
1990
- json = JSON.parse(response.body)
1991
-
1992
- expect(json).to eq([["QueryUser", nil]])
1993
- end
1994
-
1995
- context "when verbose" do
1996
- # TODO: would be nice to not have to do =true here...
1997
- let(:inputs) { { verbose: true } }
1998
-
1999
- it "lists commands" do
2000
- expect(response.status).to be(0)
2001
- json = JSON.parse(response.body)
2002
-
2003
- expect(json).to eq([["QueryUser", "Queries a user"]])
2004
- end
2005
- end
2006
- end
2007
-
2008
- context "with describe_type path" do
2009
- let(:inputs) { {} }
2010
- let(:full_command_name) { "User" }
2011
- let(:action) { "describe_type" }
2012
-
2013
- it "includes types" do
2014
- expect(response.status).to be(0)
2015
- json = JSON.parse(response.body)
2016
- expect(json["declaration_data"]["name"]).to eq("User")
2017
- end
2018
- end
2019
- end
2020
- end
2021
- end
2022
- end
2023
-
2024
- describe "#patch_up_broken_parents_for_errors_with_missing_command_parents" do
2025
- let(:fixture_path) {
2026
- "#{__dir__}/fixtures/command_connectors/manifest_with_errors_with_missing_command_parents.yaml"
2027
- }
2028
- let(:manifest_hash) do
2029
- YAML.load_file(fixture_path, aliases: true)
2030
- end
2031
-
2032
- it "fixes busted parents by leapfrogging them and patching up scoped paths/names" do
2033
- error_manifest = manifest_hash[:error][:"Foobara::Auth::FindUser::UserNotFoundError"]
2034
-
2035
- expect(error_manifest[:scoped_path]).to eq(["UserNotFoundError"])
2036
- expect(error_manifest[:parent]).to eq([:command, "Foobara::Auth::FindUser"])
2037
- expect(error_manifest[:scoped_prefix]).to be_nil
2038
- expect(error_manifest[:scoped_name]).to eq("UserNotFoundError")
2039
-
2040
- # TODO: figure out how to set up this situation instead of directly passing a manifest
2041
- # hash to a private method
2042
- patched_up_manifest = command_connector.send(
2043
- :patch_up_broken_parents_for_errors_with_missing_command_parents,
2044
- manifest_hash
2045
- )
2046
-
2047
- patched_up_error_manifest = patched_up_manifest[:error][:"Foobara::Auth::FindUser::UserNotFoundError"]
2048
-
2049
- expect(patched_up_error_manifest[:scoped_path]).to eq(["FindUser", "UserNotFoundError"])
2050
- expect(patched_up_error_manifest[:parent]).to eq([:domain, "Foobara::Auth"])
2051
- expect(patched_up_error_manifest[:scoped_prefix]).to eq(["FindUser"])
2052
- expect(patched_up_error_manifest[:scoped_name]).to eq("FindUser::UserNotFoundError")
2053
- end
2054
- end
2055
-
2056
- context "with multiple layers of inheritance with allowed_rule entries" do
2057
- let(:allowed_rule_a) do
2058
- proc { "a" }
2059
- end
2060
- # intentionally skipping b
2061
- let(:allowed_rule_c) do
2062
- proc {} # will not be allowed
2063
- end
2064
- let(:allowed_rule_d) do
2065
- proc { "d" }
2066
- end
2067
-
2068
- let(:command_connector_class_a) do
2069
- rule = allowed_rule_a
2070
- stub_class "CommandConnectorA", described_class do
2071
- register_allowed_rule :a, rule
2072
- end
2073
- end
2074
-
2075
- let(:command_connector_class_b) do
2076
- stub_class "CommandConnectorB", command_connector_class_a
2077
- end
2078
-
2079
- let(:command_connector_class_c) do
2080
- rule = allowed_rule_c
2081
- stub_class "CommandConnectorC", command_connector_class_b do
2082
- register_allowed_rule :c, rule
2083
- end
2084
- end
2085
-
2086
- let(:command_connector_class_d) do
2087
- stub_class "CommandConnectorD", command_connector_class_c
2088
- end
2089
- let(:command_connector) do
2090
- rule = allowed_rule_d
2091
- command_connector_class_d.new(requires_allowed_rule: true) do
2092
- register_allowed_rule :d, rule
2093
- end
2094
- end
2095
-
2096
- it "puts the expected allowed rules on the command connector" do
2097
- command_connector.connect(command_class, suffix: "A", allow_if: :a)
2098
- command_connector.connect(command_class, suffix: "B", allow_if: :always)
2099
- command_connector.connect(command_class, suffix: "C", allowed_rule: :c)
2100
- command_connector.connect(command_class, suffix: "D", allowed_rule: :d)
2101
-
2102
- response = command_connector.run(full_command_name: "ComputeExponentA", action:, inputs:)
2103
- expect(response.status).to be(0)
2104
- expect(response.command.allowed_rule.symbol).to be(:a)
2105
-
2106
- response = command_connector.run(full_command_name: "ComputeExponentB", action:, inputs:)
2107
- expect(response.status).to be(0)
2108
- expect(response.command.allowed_rule).to be(described_class.always_allowed_rule)
2109
-
2110
- response = command_connector.run(full_command_name: "ComputeExponentC", action:, inputs:)
2111
- expect(response.status).to be(1)
2112
- expect(response.command.allowed_rule.symbol).to be(:c)
2113
-
2114
- response = command_connector.run(full_command_name: "ComputeExponentD", action:, inputs:)
2115
- expect(response.status).to be(0)
2116
- expect(response.command.allowed_rule.symbol).to be(:d)
2117
- end
2118
- end
2119
-
2120
- context "with multiple authenticators to choose from" do
2121
- let(:authenticator_a) do
2122
- stub_class("NotApplicableAuthenticator", Foobara::CommandConnector::Authenticator) do
2123
- def initialize
2124
- super(symbol: :a, &proc { "a" })
2125
- end
2126
-
2127
- def applicable?(_request)
2128
- false
2129
- end
2130
- end
2131
- end
2132
-
2133
- let(:authenticator_b) do
2134
- stub_class("ApplicableAuthenticator", Foobara::CommandConnector::Authenticator) do
2135
- def initialize
2136
- super(symbol: :b, &proc { "b" })
2137
- end
2138
- end
2139
- end
2140
-
2141
- let(:authenticator) { [authenticator_a, authenticator_b] }
2142
- let(:requires_authentication) { true }
2143
-
2144
- it "chooses the applicable authenticator" do
2145
- expect(response.status).to be(0)
2146
- expect(response.command.authenticated_user).to eq("b")
2147
- end
2148
-
2149
- describe "#foobara_manifest" do
2150
- it "contains combined info about the authenticator" do
2151
- manifest = command_connector.foobara_manifest
2152
-
2153
- expect(manifest[:command][:ComputeExponent][:authenticator]).to eq(
2154
- symbol: :a_or_b,
2155
- explanation: "a, or b"
2156
- )
2157
- end
2158
- end
2159
- end
2160
-
2161
- context "with multiple layers of inheritance with authenticator entries" do
2162
- let(:authenticator_a) do
2163
- stub_class("SomeAuthenticator", Foobara::CommandConnector::Authenticator) do
2164
- def initialize
2165
- super(symbol: :a, &proc { ["a", "acred"] })
2166
- end
2167
- end
2168
- end
2169
- # intentionally skipping b
2170
- let(:authenticator_c) do
2171
- proc {} # will not be allowed
2172
- end
2173
- let(:authenticator_d) do
2174
- proc { "d" }
2175
- end
2176
- let(:authenticator_e) do
2177
- proc { "e" }
2178
- end
2179
-
2180
- let(:command_connector_class_a) do
2181
- authenticator = authenticator_a
2182
- stub_class "CommandConnectorA", described_class do
2183
- register_authenticator :a, authenticator
2184
- end
2185
- end
2186
-
2187
- let(:command_connector_class_b) do
2188
- stub_class "CommandConnectorB", command_connector_class_a
2189
- end
2190
-
2191
- let(:command_connector_class_c) do
2192
- authenticator = authenticator_c
2193
- stub_class "CommandConnectorC", command_connector_class_b do
2194
- register_authenticator :c, authenticator
2195
- end
2196
- end
2197
-
2198
- let(:command_connector_class_d) do
2199
- authenticator = authenticator_d
2200
- stub_class "CommandConnectorD", command_connector_class_c do
2201
- register_authenticator :d, authenticator
2202
- end
2203
- end
2204
-
2205
- let(:command_connector_class_e) do
2206
- stub_class "CommandConnectorE", command_connector_class_d
2207
- end
2208
-
2209
- let(:command_connector_a) { command_connector_class_a.new(authenticator: authenticator_a) }
2210
- let(:command_connector_b) { command_connector_class_b.new(authenticator: "a") }
2211
- let(:command_connector_c) { command_connector_class_c.new(authenticator: :a) }
2212
- let(:command_connector_d) { command_connector_class_d.new(authenticator: :c) }
2213
- let(:command_connector_e) { command_connector_class_e.new(authenticator: :d) }
2214
-
2215
- it "puts the expected allowed rules on the command connector" do
2216
- command_connector_a.connect(command_class, :requires_authentication)
2217
- command_connector_b.connect(command_class, :auth)
2218
- command_connector_c.connect(command_class, requires_authentication: true)
2219
- command_connector_d.connect(command_class, requires_authentication: true)
2220
- command_connector_e.connect(command_class, requires_authentication: true,
2221
- authenticator: [authenticator_e])
2222
-
2223
- response = command_connector_a.run(full_command_name:, action:, inputs:)
2224
- expect(response.status).to be(0)
2225
- expect(response.command.authenticated_user).to eq("a")
2226
- expect(response.command.authenticator.symbol).to be(:a)
2227
-
2228
- response = command_connector_b.run(full_command_name:, action:, inputs:)
2229
- expect(response.status).to be(0)
2230
- expect(response.command.authenticated_user).to eq("a")
2231
- expect(response.command.authenticated_credential).to eq("acred")
2232
- expect(response.command.authenticator.symbol).to be(:a)
2233
-
2234
- response = command_connector_c.run(full_command_name:, action:, inputs:)
2235
- expect(response.status).to be(0)
2236
- expect(response.command.authenticated_user).to eq("a")
2237
- expect(response.command.authenticator.symbol).to be(:a)
2238
-
2239
- response = command_connector_d.run(full_command_name:, action:, inputs:)
2240
- expect(response.status).to be(1)
2241
- expect(response.error.key).to eq("runtime.unauthenticated")
2242
- expect(response.command.authenticated_user).to be_nil
2243
- expect(response.command.authenticator.symbol).to be(:c)
2244
-
2245
- response = command_connector_e.run(full_command_name:, action:, inputs:)
2246
- expect(response.status).to be(0)
2247
- expect(response.command.authenticated_user).to eq("e")
2248
- end
2249
-
2250
- describe "#foobara_manifest" do
2251
- it "contains info about the authenticator" do
2252
- command_connector_a.connect(command_class, requires_authentication: true)
2253
- manifest = command_connector_a.foobara_manifest
2254
- expect(manifest[:command][:ComputeExponent][:authenticator]).to eq(
2255
- symbol: :a,
2256
- explanation: :a
2257
- )
2258
- end
2259
- end
2260
- end
2261
-
2262
- context "when using sugar" do
2263
- let(:command_class) do
2264
- stub_class("SomeCommand", Foobara::Command) do
2265
- inputs do
2266
- foo :string, default: "defaultfoo"
2267
- bar :string, default: "defaultbar"
2268
- baz :string, default: "defaultbaz"
2269
- end
2270
- result do
2271
- foo :string
2272
- bar :string
2273
- baz :string
2274
- end
2275
-
2276
- def execute
2277
- inputs
2278
- end
2279
- end
2280
- end
2281
- let(:full_command_name) { command_class.full_command_name }
2282
-
2283
- context "when only" do
2284
- context "with non-array" do
2285
- let(:inputs_transformers_sugar) do
2286
- { only: :foo }
2287
- end
2288
- let(:result_transformers_sugar) do
2289
- { only: :bar }
2290
- end
2291
-
2292
- let(:inputs) do
2293
- { foo: "foo" }
2294
- end
2295
-
2296
- it "can add/remove inputs/results" do
2297
- expect(response.status).to be(0)
2298
- expect(parsed_response).to eq("bar" => "defaultbar")
2299
- end
2300
- end
2301
-
2302
- context "when arrays" do
2303
- let(:inputs_transformers_sugar) do
2304
- { only: [:foo, :bar] }
2305
- end
2306
- let(:result_transformers_sugar) do
2307
- { only: [:bar, :baz] }
2308
- end
2309
- let(:inputs) do
2310
- {
2311
- foo: "foo",
2312
- bar: "bar"
2313
- }
2314
- end
2315
-
2316
- it "can add/remove inputs/results" do
2317
- expect(response.status).to be(0)
2318
- expect(parsed_response).to eq("bar" => "bar", "baz" => "defaultbaz")
2319
- end
2320
- end
2321
- end
2322
-
2323
- context "when reject" do
2324
- context "with non-array" do
2325
- let(:inputs_transformers_sugar) do
2326
- { reject: :foo }
2327
- end
2328
- let(:result_transformers_sugar) do
2329
- { reject: :bar }
2330
- end
2331
-
2332
- let(:inputs) do
2333
- {
2334
- bar: "bar",
2335
- baz: "baz"
2336
- }
2337
- end
2338
-
2339
- it "can add/remove inputs/results" do
2340
- expect(response.status).to be(0)
2341
- expect(parsed_response).to eq("foo" => "defaultfoo", "baz" => "baz")
2342
- end
2343
- end
2344
-
2345
- context "when arrays" do
2346
- let(:inputs_transformers_sugar) do
2347
- { reject: [:foo, :bar] }
2348
- end
2349
- let(:result_transformers_sugar) do
2350
- { reject: [:bar, :baz] }
2351
- end
2352
- let(:inputs) do
2353
- { baz: "baz" }
2354
- end
2355
-
2356
- it "can add/remove inputs/results" do
2357
- expect(response.status).to be(0)
2358
- expect(parsed_response).to eq("foo" => "defaultfoo")
2359
- end
2360
- end
2361
- end
2362
-
2363
- context "when set" do
2364
- context "with non-array" do
2365
- let(:inputs_transformers_sugar) do
2366
- { set: { foo: -> { "setfoo" } } }
2367
- end
2368
-
2369
- let(:inputs) do
2370
- {
2371
- bar: "bar",
2372
- baz: "baz"
2373
- }
2374
- end
2375
-
2376
- it "can add/remove inputs/results" do
2377
- expect(response.status).to be(0)
2378
- expect(parsed_response).to eq("foo" => "setfoo", "baz" => "baz", "bar" => "bar")
2379
- end
2380
- end
2381
- end
2382
-
2383
- context "when mixture of sugar and non sugar transformers" do
2384
- let(:inputs_transformers_sugar) do
2385
- [
2386
- Foobara::AttributesTransformers.only(:bar, :baz),
2387
- { only: [:bar] }
2388
- ]
2389
- end
2390
- let(:result_transformers_sugar) do
2391
- { only: [:bar, :baz] }
2392
- end
2393
- let(:inputs) do
2394
- {
2395
- bar: "bar"
2396
- }
2397
- end
2398
-
2399
- it "can add/remove inputs/results" do
2400
- expect(response.status).to be(0)
2401
- expect(parsed_response).to eq("bar" => "bar", "baz" => "defaultbaz")
2402
- end
2403
- end
2404
-
2405
- context "when using yaml sugar" do
2406
- let(:command_class) do
2407
- stub_class("SomeCommand", Foobara::Command) do
2408
- inputs do
2409
- foo :required do
2410
- foo :string, :required
2411
- bar :string, :required
2412
- end
2413
- bar :required do
2414
- foo :string, :required
2415
- bar :string, :required
2416
- end
2417
- baz :required do
2418
- foo :string, :required
2419
- bar :string, :required
2420
- end
2421
- end
2422
- result :duck
2423
-
2424
- def execute
2425
- inputs
2426
- end
2427
- end
2428
- end
2429
-
2430
- let(:inputs_transformers) do
2431
- { yaml: [:foo, :bar] }
2432
- end
2433
-
2434
- let(:inputs) do
2435
- {
2436
- foo: "---\n:foo: foofoo\n:bar: foofoofoo\n",
2437
- bar: "---\n:foo: barbar\n:bar: barbarbar\n",
2438
- baz: { foo: "bazbaz", bar: "bazbazbaz" }
2439
- }
2440
- end
2441
-
2442
- it "sets the type to a string for the yaml inputs" do
2443
- transformed_command = command_connector.transformed_command_from_name("SomeCommand")
2444
- inputs_type = transformed_command.inputs_type
2445
-
2446
- expect(inputs_type.element_types[:foo].declaration_data).to eq(:string)
2447
- expect(inputs_type.element_types[:bar].declaration_data).to eq(:string)
2448
- expect(inputs_type.element_types[:baz].declaration_data[:type]).to eq(:attributes)
2449
-
2450
- expect(response.status).to be(0)
2451
- expect(parsed_response).to eq(
2452
- "foo" => { "foo" => "foofoo", "bar" => "foofoofoo" },
2453
- "bar" => { "foo" => "barbar", "bar" => "barbarbar" },
2454
- "baz" => { "foo" => "bazbaz", "bar" => "bazbazbaz" }
2455
- )
2456
- end
2457
- end
2458
- end
2459
- end
2460
- end