embulk-output-kintone 1.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +65 -1
  3. data/build.gradle +1 -0
  4. data/classpath/commons-csv-1.9.0.jar +0 -0
  5. data/classpath/embulk-output-kintone-1.2.0.jar +0 -0
  6. data/classpath/externalsortinginjava-0.6.2.jar +0 -0
  7. data/classpath/{shadow-kintone-java-client-1.0.0-all.jar → shadow-kintone-java-client-1.2.0-all.jar} +0 -0
  8. data/src/main/java/org/embulk/output/kintone/KintoneClient.java +117 -0
  9. data/src/main/java/org/embulk/output/kintone/KintoneColumnOption.java +5 -0
  10. data/src/main/java/org/embulk/output/kintone/KintoneColumnType.java +226 -5
  11. data/src/main/java/org/embulk/output/kintone/KintoneColumnVisitor.java +82 -13
  12. data/src/main/java/org/embulk/output/kintone/KintoneMode.java +52 -4
  13. data/src/main/java/org/embulk/output/kintone/KintoneOutputPlugin.java +12 -20
  14. data/src/main/java/org/embulk/output/kintone/KintonePageOutput.java +123 -127
  15. data/src/main/java/org/embulk/output/kintone/KintoneSortColumn.java +33 -0
  16. data/src/main/java/org/embulk/output/kintone/PluginTask.java +32 -0
  17. data/src/main/java/org/embulk/output/kintone/deserializer/DeserializeApplier.java +19 -0
  18. data/src/main/java/org/embulk/output/kintone/deserializer/DeserializeException.java +7 -0
  19. data/src/main/java/org/embulk/output/kintone/deserializer/Deserializer.java +279 -0
  20. data/src/main/java/org/embulk/output/kintone/record/Id.java +18 -0
  21. data/src/main/java/org/embulk/output/kintone/record/IdOrUpdateKey.java +45 -0
  22. data/src/main/java/org/embulk/output/kintone/record/Skip.java +14 -0
  23. data/src/main/java/org/embulk/output/kintone/reducer/CSVInputColumnVisitor.java +78 -0
  24. data/src/main/java/org/embulk/output/kintone/reducer/CSVOutputColumnVisitor.java +79 -0
  25. data/src/main/java/org/embulk/output/kintone/reducer/ReduceException.java +11 -0
  26. data/src/main/java/org/embulk/output/kintone/reducer/ReduceType.java +190 -0
  27. data/src/main/java/org/embulk/output/kintone/reducer/ReducedPageOutput.java +100 -0
  28. data/src/main/java/org/embulk/output/kintone/reducer/Reducer.java +355 -0
  29. data/src/main/java/org/embulk/output/kintone/util/Lazy.java +20 -0
  30. data/src/test/java/org/embulk/output/kintone/KintoneClientTest.java +139 -0
  31. data/src/test/java/org/embulk/output/kintone/KintoneColumnOptionBuilder.java +7 -0
  32. data/src/test/java/org/embulk/output/kintone/KintoneColumnTypeTest.java +194 -0
  33. data/src/test/java/org/embulk/output/kintone/KintoneColumnVisitorTest.java +183 -64
  34. data/src/test/java/org/embulk/output/kintone/KintoneColumnVisitorVerifier.java +19 -9
  35. data/src/test/java/org/embulk/output/kintone/KintonePageOutputVerifier.java +120 -51
  36. data/src/test/java/org/embulk/output/kintone/MockClient.java +112 -0
  37. data/src/test/java/org/embulk/output/kintone/TestKintoneOutputPlugin.java +147 -22
  38. data/src/test/java/org/embulk/output/kintone/TestTaskMode.java +1 -0
  39. data/src/test/java/org/embulk/output/kintone/TestTaskReduce.java +47 -0
  40. data/src/test/java/org/embulk/output/kintone/TestTaskReduceException.java +50 -0
  41. data/src/test/java/org/embulk/output/kintone/TestTaskReduceSubtable.java +47 -0
  42. data/src/test/java/org/embulk/output/kintone/TestTaskSkip.java +80 -0
  43. data/src/test/java/org/embulk/output/kintone/TestTaskSkipId.java +80 -0
  44. data/src/test/java/org/embulk/output/kintone/deserializer/DeserializerTest.java +165 -0
  45. data/src/test/java/org/embulk/output/kintone/reducer/ReduceTypeTest.java +154 -0
  46. data/src/test/resources/org/embulk/output/kintone/client/config.yml +1 -0
  47. data/src/test/resources/org/embulk/output/kintone/task/config.yml +2 -1
  48. data/src/test/resources/org/embulk/output/kintone/task/mode/config.yml +6 -0
  49. data/src/test/resources/org/embulk/output/kintone/task/mode/input.csv +7 -7
  50. data/src/test/resources/org/embulk/output/kintone/task/mode/insert_add_records.jsonl +6 -6
  51. data/src/test/resources/org/embulk/output/kintone/task/mode/{insert_add_ignore_nulls_records.jsonl → insert_ignore_nulls_add_records.jsonl} +2 -2
  52. data/src/test/resources/org/embulk/output/kintone/task/mode/{insert_add_prefer_nulls_records.jsonl → insert_prefer_nulls_add_records.jsonl} +6 -6
  53. data/src/test/resources/org/embulk/output/kintone/task/mode/{update_update_ignore_nulls_records.jsonl → update_ignore_nulls_update_records.jsonl} +2 -2
  54. data/src/test/resources/org/embulk/output/kintone/task/mode/{update_update_prefer_nulls_records.jsonl → update_prefer_nulls_update_records.jsonl} +3 -3
  55. data/src/test/resources/org/embulk/output/kintone/task/mode/update_update_records.jsonl +6 -6
  56. data/src/test/resources/org/embulk/output/kintone/task/mode/{upsert_add_records.jsonl → upsert_never_skip_add_records.jsonl} +2 -2
  57. data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_never_skip_double_single_line_text_add_values.json +1 -0
  58. data/src/test/resources/org/embulk/output/kintone/task/mode/{upsert_update_ignore_nulls_records.jsonl → upsert_never_skip_ignore_nulls_update_records.jsonl} +2 -2
  59. data/src/test/resources/org/embulk/output/kintone/task/mode/{upsert_add_prefer_nulls_records.jsonl → upsert_never_skip_prefer_nulls_add_records.jsonl} +3 -3
  60. data/src/test/resources/org/embulk/output/kintone/task/mode/{upsert_update_prefer_nulls_records.jsonl → upsert_never_skip_prefer_nulls_update_records.jsonl} +3 -3
  61. data/src/test/resources/org/embulk/output/kintone/task/mode/{upsert_update_records.jsonl → upsert_never_skip_update_records.jsonl} +4 -4
  62. data/src/test/resources/org/embulk/output/kintone/task/reduce/config.yml +171 -0
  63. data/src/test/resources/org/embulk/output/kintone/task/reduce/input.csv +7 -0
  64. data/src/test/resources/org/embulk/output/kintone/task/reduce/insert_add_records.jsonl +6 -0
  65. data/src/test/resources/org/embulk/output/kintone/task/reduce/insert_ignore_nulls_add_records.jsonl +6 -0
  66. data/src/test/resources/org/embulk/output/kintone/task/reduce/insert_prefer_nulls_add_records.jsonl +6 -0
  67. data/src/test/resources/org/embulk/output/kintone/task/reduce/update_ignore_nulls_update_records.jsonl +3 -0
  68. data/src/test/resources/org/embulk/output/kintone/task/reduce/update_prefer_nulls_update_records.jsonl +3 -0
  69. data/src/test/resources/org/embulk/output/kintone/task/reduce/update_update_records.jsonl +6 -0
  70. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_never_skip_add_records.jsonl +2 -0
  71. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_never_skip_double_single_line_text_add_values.json +1 -0
  72. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_never_skip_double_single_line_text_values.json +1 -0
  73. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_never_skip_ignore_nulls_add_records.jsonl +3 -0
  74. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_never_skip_ignore_nulls_double_single_line_text_values.json +1 -0
  75. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_never_skip_ignore_nulls_update_records.jsonl +3 -0
  76. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_never_skip_prefer_nulls_add_records.jsonl +3 -0
  77. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_never_skip_prefer_nulls_double_single_line_text_values.json +1 -0
  78. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_never_skip_prefer_nulls_update_records.jsonl +3 -0
  79. data/src/test/resources/org/embulk/output/kintone/task/reduce/upsert_never_skip_update_records.jsonl +4 -0
  80. data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/config.yml +36 -0
  81. data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/derived_columns.json +1 -0
  82. data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/input.csv +13 -0
  83. data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/insert_add_records.jsonl +2 -0
  84. data/src/test/resources/org/embulk/output/kintone/task/reduce_exception/update_update_records.jsonl +2 -0
  85. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/config.yml +343 -0
  86. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/derived_columns.json +1 -0
  87. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/input.csv +13 -0
  88. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/insert_add_records.jsonl +6 -0
  89. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/insert_ignore_nulls_add_records.jsonl +6 -0
  90. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/insert_prefer_nulls_add_records.jsonl +6 -0
  91. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/update_ignore_nulls_update_records.jsonl +3 -0
  92. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/update_prefer_nulls_update_records.jsonl +3 -0
  93. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/update_update_records.jsonl +6 -0
  94. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_never_skip_double_single_line_text_values.json +1 -0
  95. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_never_skip_ignore_nulls_add_records.jsonl +3 -0
  96. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_never_skip_ignore_nulls_double_single_line_text_values.json +1 -0
  97. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_never_skip_ignore_nulls_update_records.jsonl +3 -0
  98. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_never_skip_prefer_nulls_add_records.jsonl +3 -0
  99. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_never_skip_prefer_nulls_double_single_line_text_values.json +1 -0
  100. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_never_skip_prefer_nulls_update_records.jsonl +3 -0
  101. data/src/test/resources/org/embulk/output/kintone/task/reduce_subtable/upsert_never_skip_update_records.jsonl +6 -0
  102. data/src/test/resources/org/embulk/output/kintone/task/skip/config.yml +1 -0
  103. data/src/test/resources/org/embulk/output/kintone/task/skip/input.csv +7 -0
  104. data/src/test/resources/org/embulk/output/kintone/task/skip/insert_add_records.jsonl +6 -0
  105. data/src/test/resources/org/embulk/output/kintone/task/skip/insert_always_skip_add_records.jsonl +6 -0
  106. data/src/test/resources/org/embulk/output/kintone/task/skip/insert_always_skip_prefer_nulls_add_records.jsonl +6 -0
  107. data/src/test/resources/org/embulk/output/kintone/task/skip/insert_never_skip_add_records.jsonl +6 -0
  108. data/src/test/resources/org/embulk/output/kintone/task/skip/insert_never_skip_prefer_nulls_add_records.jsonl +6 -0
  109. data/src/test/resources/org/embulk/output/kintone/task/skip/insert_prefer_nulls_add_records.jsonl +6 -0
  110. data/src/test/resources/org/embulk/output/kintone/task/skip/update_always_skip_long_number_add_values.json +1 -0
  111. data/src/test/resources/org/embulk/output/kintone/task/skip/update_always_skip_long_number_values.json +1 -0
  112. data/src/test/resources/org/embulk/output/kintone/task/skip/update_always_skip_prefer_nulls_long_number_add_values.json +1 -0
  113. data/src/test/resources/org/embulk/output/kintone/task/skip/update_always_skip_prefer_nulls_long_number_values.json +1 -0
  114. data/src/test/resources/org/embulk/output/kintone/task/skip/update_always_skip_prefer_nulls_update_records.jsonl +2 -0
  115. data/src/test/resources/org/embulk/output/kintone/task/skip/update_always_skip_update_records.jsonl +5 -0
  116. data/src/test/resources/org/embulk/output/kintone/task/skip/update_never_skip_update_records.jsonl +6 -0
  117. data/src/test/resources/org/embulk/output/kintone/task/skip/update_prefer_nulls_update_records.jsonl +3 -0
  118. data/src/test/resources/org/embulk/output/kintone/task/skip/update_update_records.jsonl +6 -0
  119. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_add_records.jsonl +1 -0
  120. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_always_skip_prefer_nulls_string_single_line_text_add_values.json +1 -0
  121. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_always_skip_prefer_nulls_string_single_line_text_values.json +1 -0
  122. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_always_skip_prefer_nulls_update_records.jsonl +2 -0
  123. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_always_skip_string_single_line_text_add_values.json +1 -0
  124. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_always_skip_string_single_line_text_values.json +1 -0
  125. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_always_skip_update_records.jsonl +2 -0
  126. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_add_records.jsonl +4 -0
  127. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_prefer_nulls_add_records.jsonl +4 -0
  128. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_prefer_nulls_string_single_line_text_add_values.json +1 -0
  129. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_prefer_nulls_string_single_line_text_values.json +1 -0
  130. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_prefer_nulls_update_records.jsonl +2 -0
  131. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_string_single_line_text_add_values.json +1 -0
  132. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_string_single_line_text_values.json +1 -0
  133. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_never_skip_update_records.jsonl +2 -0
  134. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_prefer_nulls_add_records.jsonl +1 -0
  135. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_prefer_nulls_string_single_line_text_add_values.json +1 -0
  136. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_prefer_nulls_string_single_line_text_values.json +1 -0
  137. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_prefer_nulls_update_records.jsonl +2 -0
  138. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_string_single_line_text_add_values.json +1 -0
  139. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_string_single_line_text_values.json +1 -0
  140. data/src/test/resources/org/embulk/output/kintone/task/skip/upsert_update_records.jsonl +2 -0
  141. data/src/test/resources/org/embulk/output/kintone/task/skip_id/config.yml +1 -0
  142. data/src/test/resources/org/embulk/output/kintone/task/skip_id/input.csv +7 -0
  143. data/src/test/resources/org/embulk/output/kintone/task/skip_id/insert_add_records.jsonl +6 -0
  144. data/src/test/resources/org/embulk/output/kintone/task/skip_id/insert_always_skip_add_records.jsonl +6 -0
  145. data/src/test/resources/org/embulk/output/kintone/task/skip_id/insert_always_skip_prefer_nulls_add_records.jsonl +6 -0
  146. data/src/test/resources/org/embulk/output/kintone/task/skip_id/insert_never_skip_add_records.jsonl +6 -0
  147. data/src/test/resources/org/embulk/output/kintone/task/skip_id/insert_never_skip_prefer_nulls_add_records.jsonl +6 -0
  148. data/src/test/resources/org/embulk/output/kintone/task/skip_id/insert_prefer_nulls_add_records.jsonl +6 -0
  149. data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_always_skip__id_add_values.json +1 -0
  150. data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_always_skip__id_values.json +1 -0
  151. data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_always_skip_prefer_nulls__id_add_values.json +1 -0
  152. data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_always_skip_prefer_nulls__id_values.json +1 -0
  153. data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_always_skip_prefer_nulls_update_records.jsonl +2 -0
  154. data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_always_skip_update_records.jsonl +5 -0
  155. data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_never_skip_update_records.jsonl +6 -0
  156. data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_prefer_nulls_update_records.jsonl +3 -0
  157. data/src/test/resources/org/embulk/output/kintone/task/skip_id/update_update_records.jsonl +6 -0
  158. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert__id_add_values.json +1 -0
  159. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert__id_values.json +1 -0
  160. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_always_skip__id_add_values.json +1 -0
  161. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_always_skip__id_values.json +1 -0
  162. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_always_skip_prefer_nulls__id_add_values.json +1 -0
  163. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_always_skip_prefer_nulls__id_values.json +1 -0
  164. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_always_skip_prefer_nulls_update_records.jsonl +2 -0
  165. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_always_skip_update_records.jsonl +5 -0
  166. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip__id_add_values.json +1 -0
  167. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip__id_values.json +1 -0
  168. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip_add_records.jsonl +1 -0
  169. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip_prefer_nulls__id_add_values.json +1 -0
  170. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip_prefer_nulls__id_values.json +1 -0
  171. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip_prefer_nulls_add_records.jsonl +4 -0
  172. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip_prefer_nulls_update_records.jsonl +2 -0
  173. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_never_skip_update_records.jsonl +5 -0
  174. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_prefer_nulls__id_add_values.json +1 -0
  175. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_prefer_nulls__id_values.json +1 -0
  176. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_prefer_nulls_add_records.jsonl +3 -0
  177. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_prefer_nulls_update_records.jsonl +2 -0
  178. data/src/test/resources/org/embulk/output/kintone/task/skip_id/upsert_update_records.jsonl +5 -0
  179. metadata +163 -17
  180. data/classpath/embulk-output-kintone-1.0.0.jar +0 -0
  181. /data/src/test/resources/org/embulk/output/kintone/task/mode/{values.json → upsert_never_skip_double_single_line_text_values.json} +0 -0
  182. /data/src/test/resources/org/embulk/output/kintone/task/mode/{upsert_add_ignore_nulls_records.jsonl → upsert_never_skip_ignore_nulls_add_records.jsonl} +0 -0
  183. /data/src/test/resources/org/embulk/output/kintone/task/mode/{values_ignore_nulls.json → upsert_never_skip_ignore_nulls_double_single_line_text_values.json} +0 -0
  184. /data/src/test/resources/org/embulk/output/kintone/task/mode/{values_prefer_nulls.json → upsert_never_skip_prefer_nulls_double_single_line_text_values.json} +0 -0
@@ -1,62 +1,74 @@
1
1
  package org.embulk.output.kintone;
2
2
 
3
+ import static org.embulk.output.kintone.deserializer.DeserializerTest.assertTableRows;
3
4
  import static org.hamcrest.MatcherAssert.assertThat;
4
5
  import static org.hamcrest.Matchers.is;
5
- import static org.mockito.ArgumentMatchers.anyList;
6
6
  import static org.mockito.ArgumentMatchers.eq;
7
- import static org.mockito.ArgumentMatchers.matches;
7
+ import static org.mockito.Mockito.CALLS_REAL_METHODS;
8
8
  import static org.mockito.Mockito.atLeast;
9
- import static org.mockito.Mockito.mock;
10
9
  import static org.mockito.Mockito.mockStatic;
11
10
  import static org.mockito.Mockito.verify;
12
- import static org.mockito.Mockito.when;
13
11
 
14
- import com.kintone.client.AppClient;
15
- import com.kintone.client.KintoneClient;
16
- import com.kintone.client.KintoneClientBuilder;
17
12
  import com.kintone.client.RecordClient;
18
- import com.kintone.client.api.record.GetRecordsByCursorResponseBody;
19
- import com.kintone.client.model.app.field.FieldProperty;
20
- import com.kintone.client.model.app.field.NumberFieldProperty;
21
- import com.kintone.client.model.app.field.SingleLineTextFieldProperty;
13
+ import com.kintone.client.model.record.FieldType;
22
14
  import com.kintone.client.model.record.FieldValue;
23
15
  import com.kintone.client.model.record.NumberFieldValue;
24
16
  import com.kintone.client.model.record.Record;
25
17
  import com.kintone.client.model.record.RecordForUpdate;
26
18
  import com.kintone.client.model.record.SingleLineTextFieldValue;
19
+ import com.kintone.client.model.record.SubtableFieldValue;
27
20
  import com.kintone.client.model.record.UpdateKey;
28
21
  import java.math.BigDecimal;
29
22
  import java.util.Collection;
30
23
  import java.util.Collections;
31
24
  import java.util.List;
32
- import java.util.Map;
25
+ import java.util.function.Function;
33
26
  import java.util.stream.Collectors;
34
27
  import java.util.stream.IntStream;
35
28
  import org.embulk.config.TaskReport;
29
+ import org.embulk.deps.buffer.PooledBufferAllocator;
30
+ import org.embulk.output.kintone.record.Id;
31
+ import org.embulk.spi.BufferAllocator;
32
+ import org.embulk.spi.Exec;
36
33
  import org.embulk.spi.Page;
37
34
  import org.embulk.spi.TransactionalPageOutput;
38
35
  import org.mockito.ArgumentCaptor;
39
36
  import org.mockito.MockedStatic;
37
+ import org.msgpack.value.StringValue;
38
+ import org.msgpack.value.ValueFactory;
40
39
 
41
40
  public class KintonePageOutputVerifier implements TransactionalPageOutput {
42
41
  private final TransactionalPageOutput transactionalPageOutput;
43
42
  private final String domain;
44
43
  private final String field;
45
44
  private final List<String> values;
45
+ private final List<String> addValues;
46
46
  private final List<Record> addRecords;
47
47
  private final List<RecordForUpdate> updateRecords;
48
48
 
49
+ public KintonePageOutputVerifier(
50
+ String domain,
51
+ String field,
52
+ List<String> values,
53
+ List<String> addValues,
54
+ List<Record> addRecords,
55
+ List<RecordForUpdate> updateRecords) {
56
+ this(null, domain, field, values, addValues, addRecords, updateRecords);
57
+ }
58
+
49
59
  public KintonePageOutputVerifier(
50
60
  TransactionalPageOutput transactionalPageOutput,
51
61
  String domain,
52
62
  String field,
53
63
  List<String> values,
64
+ List<String> addValues,
54
65
  List<Record> addRecords,
55
66
  List<RecordForUpdate> updateRecords) {
56
67
  this.transactionalPageOutput = transactionalPageOutput;
57
68
  this.domain = domain;
58
69
  this.field = field;
59
70
  this.values = values;
71
+ this.addValues = addValues;
60
72
  this.addRecords = addRecords;
61
73
  this.updateRecords = updateRecords;
62
74
  }
@@ -73,6 +85,9 @@ public class KintonePageOutputVerifier implements TransactionalPageOutput {
73
85
 
74
86
  @Override
75
87
  public void close() {
88
+ if (transactionalPageOutput == null) {
89
+ return;
90
+ }
76
91
  transactionalPageOutput.close();
77
92
  }
78
93
 
@@ -86,45 +101,27 @@ public class KintonePageOutputVerifier implements TransactionalPageOutput {
86
101
  return transactionalPageOutput.commit();
87
102
  }
88
103
 
89
- public void runWithMock(Runnable runnable) {
104
+ public void runWithMock(MockClient.Runnable runnable) {
90
105
  try {
91
- runWithMockClient(runnable);
106
+ runWithMockExec(runnable);
92
107
  } catch (Exception e) {
93
108
  throw new RuntimeException(e);
94
109
  }
95
110
  }
96
111
 
97
- private void runWithMockClient(Runnable runnable) throws Exception {
98
- @SuppressWarnings("unchecked")
99
- Map<String, FieldProperty> mockFormFields = mock(Map.class);
100
- when(mockFormFields.get(matches("^.*_single_line_text$")))
101
- .thenReturn(new SingleLineTextFieldProperty());
102
- when(mockFormFields.get(matches("^.*_number$"))).thenReturn(new NumberFieldProperty());
103
- AppClient mockAppClient = mock(AppClient.class);
104
- when(mockAppClient.getFormFields(eq(0L))).thenReturn(mockFormFields);
105
- GetRecordsByCursorResponseBody mockGetRecordsByCursorResponseBody =
106
- mock(GetRecordsByCursorResponseBody.class);
107
- when(mockGetRecordsByCursorResponseBody.getRecords())
108
- .thenReturn(updateRecords.stream().map(this::getRecord).collect(Collectors.toList()));
109
- when(mockGetRecordsByCursorResponseBody.hasNext()).thenReturn(false);
110
- RecordClient mockRecordClient = mock(RecordClient.class);
111
- when(mockRecordClient.createCursor(eq(0L), eq(getFields()), eq(getQuery()))).thenReturn("id");
112
- when(mockRecordClient.getRecordsByCursor(eq("id")))
113
- .thenReturn(mockGetRecordsByCursorResponseBody);
114
- when(mockRecordClient.addRecords(eq(0L), anyList())).thenReturn(Collections.emptyList());
115
- when(mockRecordClient.updateRecords(eq(0L), anyList())).thenReturn(Collections.emptyList());
116
- KintoneClient mockKintoneClient = mock(KintoneClient.class);
117
- when(mockKintoneClient.app()).thenReturn(mockAppClient);
118
- when(mockKintoneClient.record()).thenReturn(mockRecordClient);
119
- KintoneClientBuilder mockKintoneClientBuilder = mock(KintoneClientBuilder.class);
120
- when(mockKintoneClientBuilder.authByApiToken(eq("token"))).thenReturn(mockKintoneClientBuilder);
121
- when(mockKintoneClientBuilder.build()).thenReturn(mockKintoneClient);
122
- try (MockedStatic<KintoneClientBuilder> mocked = mockStatic(KintoneClientBuilder.class)) {
123
- mocked
124
- .when(() -> KintoneClientBuilder.create(String.format("https://%s", domain)))
125
- .thenReturn(mockKintoneClientBuilder);
126
- runnable.run();
112
+ private void runWithMockExec(MockClient.Runnable runnable) throws Exception {
113
+ BufferAllocator bufferAllocator = PooledBufferAllocator.create(1024 * 1024);
114
+ try (MockedStatic<Exec> mocked = mockStatic(Exec.class, CALLS_REAL_METHODS)) {
115
+ mocked.when(Exec::getBufferAllocator).thenReturn(bufferAllocator);
116
+ runWithMockClient(runnable);
127
117
  }
118
+ }
119
+
120
+ private void runWithMockClient(MockClient.Runnable runnable) throws Exception {
121
+ assertValues(domain, getValues(), sorted(values));
122
+ MockClient mockClient = new MockClient(domain, getRecords(), getFields(), getQuery());
123
+ RecordClient mockRecordClient = mockClient.getMockRecordClient();
124
+ mockClient.run(runnable);
128
125
  @SuppressWarnings("unchecked")
129
126
  ArgumentCaptor<List<Record>> addRecordsArgumentCaptor = ArgumentCaptor.forClass(List.class);
130
127
  verify(mockRecordClient, atLeast(0)).addRecords(eq(0L), addRecordsArgumentCaptor.capture());
@@ -147,8 +144,40 @@ public class KintonePageOutputVerifier implements TransactionalPageOutput {
147
144
  updateRecords);
148
145
  }
149
146
 
147
+ private List<String> getValues() {
148
+ if (values.isEmpty() || updateRecords.isEmpty()) {
149
+ return values;
150
+ }
151
+ Function<FieldValue, StringValue> toValue =
152
+ value ->
153
+ field.matches("^.*_number$")
154
+ ? ValueFactory.newString(((NumberFieldValue) value).getValue().toPlainString())
155
+ : ValueFactory.newString(((SingleLineTextFieldValue) value).getValue());
156
+ Function<Record, String> toJson =
157
+ record ->
158
+ Id.FIELD.equals(field)
159
+ ? ValueFactory.newString(record.getId().toString()).toJson()
160
+ : toValue.apply(record.getFieldValue(field)).toJson();
161
+ List<String> values = getRecords().stream().map(toJson).collect(Collectors.toList());
162
+ values.addAll(addValues);
163
+ return sorted(values);
164
+ }
165
+
166
+ private List<Record> getRecords() {
167
+ return updateRecords.stream().map(this::getRecord).collect(Collectors.toList());
168
+ }
169
+
150
170
  private Record getRecord(RecordForUpdate updateRecord) {
171
+ Long id = updateRecord.getId();
151
172
  UpdateKey key = updateRecord.getUpdateKey();
173
+ return id != null ? getRecord(id) : getRecord(key);
174
+ }
175
+
176
+ private Record getRecord(Long id) {
177
+ return new Record(id, null);
178
+ }
179
+
180
+ private Record getRecord(UpdateKey key) {
152
181
  String field = key.getField();
153
182
  Object value = key.getValue();
154
183
  return new Record()
@@ -167,6 +196,18 @@ public class KintonePageOutputVerifier implements TransactionalPageOutput {
167
196
  return String.format("%s in (%s)", field, String.join(",", values));
168
197
  }
169
198
 
199
+ private static void assertValues(String domain, List<String> actual, List<String> expected) {
200
+ assertThat(domain, actual.size(), is(expected.size()));
201
+ // spotless:off
202
+ IntStream.range(0, actual.size()).forEach(index -> assertValue(domain, index, actual.get(index), expected.get(index)));
203
+ // spotless:on
204
+ }
205
+
206
+ private static void assertValue(String domain, int index, String actual, String expected) {
207
+ String reason = String.format("%s:%d", domain, index);
208
+ assertThat(reason, actual, is(expected));
209
+ }
210
+
170
211
  private static void assertRecords(String domain, List<Record> actual, List<Record> expected) {
171
212
  assertThat(domain, actual.size(), is(expected.size()));
172
213
  // spotless:off
@@ -181,16 +222,32 @@ public class KintonePageOutputVerifier implements TransactionalPageOutput {
181
222
  assertThat(reason, actual.getFieldCodes(true), is(expected.getFieldCodes(true)));
182
223
  // spotless:off
183
224
  actual.getFieldCodes(true).forEach(fieldCode -> assertFieldValue(domain, index, fieldCode, actual.getFieldValue(fieldCode), expected.getFieldValue(fieldCode)));
225
+ actual.getFieldCodes(true).forEach(fieldCode -> assertSubtableFieldValue(domain, index, fieldCode, actual.getFieldValue(fieldCode), expected.getFieldValue(fieldCode)));
184
226
  // spotless:on
185
227
  }
186
228
 
187
229
  private static void assertFieldValue(
188
230
  String domain, int index, String fieldCode, FieldValue actual, FieldValue expected) {
231
+ if (actual.getType() == FieldType.SUBTABLE) {
232
+ return;
233
+ }
189
234
  String reason = String.format("%s:%d:%s", domain, index, fieldCode);
190
235
  assertThat(reason, actual.getType(), is(expected.getType()));
191
236
  assertThat(reason, actual, is(expected));
192
237
  }
193
238
 
239
+ private static void assertSubtableFieldValue(
240
+ String domain, int index, String fieldCode, FieldValue actual, FieldValue expected) {
241
+ if (actual.getType() != FieldType.SUBTABLE) {
242
+ return;
243
+ }
244
+ String reason = String.format("%s:%d:%s", domain, index, fieldCode);
245
+ assertThat(reason, actual.getType(), is(expected.getType()));
246
+ // spotless:off
247
+ assertTableRows(reason, ((SubtableFieldValue) actual).getRows(), ((SubtableFieldValue) expected).getRows());
248
+ // spotless:on
249
+ }
250
+
194
251
  private static void assertRecordForUpdates(
195
252
  String domain, List<RecordForUpdate> actual, List<RecordForUpdate> expected) {
196
253
  assertThat(domain, actual.size(), is(expected.size()));
@@ -202,20 +259,32 @@ public class KintonePageOutputVerifier implements TransactionalPageOutput {
202
259
  private static void assertRecordForUpdate(
203
260
  String domain, int index, RecordForUpdate actual, RecordForUpdate expected) {
204
261
  String reason = String.format("%s:%d", domain, index);
205
- assertThat(reason, actual.getId(), is(expected.getId()));
206
- assertUpdateKey(domain, index, actual.getUpdateKey(), expected.getUpdateKey());
262
+ assertId(domain, index, actual, expected);
263
+ assertUpdateKey(domain, index, actual, expected);
207
264
  assertRecord(domain, index, actual.getRecord(), expected.getRecord());
208
265
  assertThat(reason, actual.getRevision(), is(expected.getRevision()));
209
266
  }
210
267
 
268
+ private static void assertId(
269
+ String domain, int index, RecordForUpdate actual, RecordForUpdate expected) {
270
+ if (actual.getUpdateKey() != null && expected.getUpdateKey() != null) {
271
+ return;
272
+ }
273
+ String reason = String.format("%s:%d", domain, index);
274
+ assertThat(reason, actual.getId(), is(expected.getId()));
275
+ }
276
+
211
277
  private static void assertUpdateKey(
212
- String domain, int index, UpdateKey actual, UpdateKey expected) {
278
+ String domain, int index, RecordForUpdate actual, RecordForUpdate expected) {
279
+ if (actual.getId() != null && expected.getId() != null) {
280
+ return;
281
+ }
213
282
  String reason = String.format("%s:%d", domain, index);
214
- assertThat(reason, actual.getField(), is(expected.getField()));
215
- assertThat(reason, actual.getValue(), is(expected.getValue()));
283
+ assertThat(reason, actual.getUpdateKey().getField(), is(expected.getUpdateKey().getField()));
284
+ assertThat(reason, actual.getUpdateKey().getValue(), is(expected.getUpdateKey().getValue()));
216
285
  }
217
286
 
218
- public interface Runnable {
219
- void run() throws Exception;
287
+ private static <T> List<T> sorted(List<T> list) {
288
+ return list.stream().sorted().collect(Collectors.toList());
220
289
  }
221
290
  }
@@ -0,0 +1,112 @@
1
+ package org.embulk.output.kintone;
2
+
3
+ import static org.mockito.ArgumentMatchers.anyList;
4
+ import static org.mockito.ArgumentMatchers.eq;
5
+ import static org.mockito.ArgumentMatchers.matches;
6
+ import static org.mockito.Mockito.mock;
7
+ import static org.mockito.Mockito.mockStatic;
8
+ import static org.mockito.Mockito.when;
9
+
10
+ import com.kintone.client.AppClient;
11
+ import com.kintone.client.KintoneClient;
12
+ import com.kintone.client.KintoneClientBuilder;
13
+ import com.kintone.client.RecordClient;
14
+ import com.kintone.client.api.record.GetRecordsByCursorResponseBody;
15
+ import com.kintone.client.model.app.field.CheckBoxFieldProperty;
16
+ import com.kintone.client.model.app.field.DateFieldProperty;
17
+ import com.kintone.client.model.app.field.DateTimeFieldProperty;
18
+ import com.kintone.client.model.app.field.DropDownFieldProperty;
19
+ import com.kintone.client.model.app.field.FieldProperty;
20
+ import com.kintone.client.model.app.field.FileFieldProperty;
21
+ import com.kintone.client.model.app.field.GroupSelectFieldProperty;
22
+ import com.kintone.client.model.app.field.LinkFieldProperty;
23
+ import com.kintone.client.model.app.field.MultiLineTextFieldProperty;
24
+ import com.kintone.client.model.app.field.MultiSelectFieldProperty;
25
+ import com.kintone.client.model.app.field.NumberFieldProperty;
26
+ import com.kintone.client.model.app.field.OrganizationSelectFieldProperty;
27
+ import com.kintone.client.model.app.field.RadioButtonFieldProperty;
28
+ import com.kintone.client.model.app.field.RichTextFieldProperty;
29
+ import com.kintone.client.model.app.field.SingleLineTextFieldProperty;
30
+ import com.kintone.client.model.app.field.SubtableFieldProperty;
31
+ import com.kintone.client.model.app.field.TimeFieldProperty;
32
+ import com.kintone.client.model.app.field.UserSelectFieldProperty;
33
+ import com.kintone.client.model.record.Record;
34
+ import java.util.Collections;
35
+ import java.util.List;
36
+ import java.util.Map;
37
+ import org.mockito.MockedStatic;
38
+
39
+ public class MockClient {
40
+ private final String domain;
41
+ private final List<Record> records;
42
+ private final List<String> fields;
43
+ private final String query;
44
+ private final RecordClient mockRecordClient;
45
+
46
+ public MockClient(String domain, List<Record> records, List<String> fields, String query) {
47
+ this.domain = domain;
48
+ this.records = records;
49
+ this.fields = fields;
50
+ this.query = query;
51
+ mockRecordClient = mock(RecordClient.class);
52
+ }
53
+
54
+ public RecordClient getMockRecordClient() {
55
+ return mockRecordClient;
56
+ }
57
+
58
+ public void run(Runnable runnable) throws Exception {
59
+ @SuppressWarnings("unchecked")
60
+ Map<String, FieldProperty> mockFormFields = mock(Map.class);
61
+ when(mockFormFields.get(matches("^.*_single_line_text$")))
62
+ .thenReturn(new SingleLineTextFieldProperty());
63
+ when(mockFormFields.get(matches("^.*_multi_line_text$")))
64
+ .thenReturn(new MultiLineTextFieldProperty());
65
+ when(mockFormFields.get(matches("^.*_rich_text$"))).thenReturn(new RichTextFieldProperty());
66
+ when(mockFormFields.get(matches("^.*_number$"))).thenReturn(new NumberFieldProperty());
67
+ when(mockFormFields.get(matches("^.*_check_box$"))).thenReturn(new CheckBoxFieldProperty());
68
+ when(mockFormFields.get(matches("^.*_radio_button$")))
69
+ .thenReturn(new RadioButtonFieldProperty());
70
+ when(mockFormFields.get(matches("^.*_multi_select$")))
71
+ .thenReturn(new MultiSelectFieldProperty());
72
+ when(mockFormFields.get(matches("^.*_drop_down$"))).thenReturn(new DropDownFieldProperty());
73
+ when(mockFormFields.get(matches("^.*_user_select$"))).thenReturn(new UserSelectFieldProperty());
74
+ when(mockFormFields.get(matches("^.*_organization_select$")))
75
+ .thenReturn(new OrganizationSelectFieldProperty());
76
+ when(mockFormFields.get(matches("^.*_group_select$")))
77
+ .thenReturn(new GroupSelectFieldProperty());
78
+ when(mockFormFields.get(matches("^.*_date$"))).thenReturn(new DateFieldProperty());
79
+ when(mockFormFields.get(matches("^.*_time$"))).thenReturn(new TimeFieldProperty());
80
+ when(mockFormFields.get(matches("^.*_datetime$"))).thenReturn(new DateTimeFieldProperty());
81
+ when(mockFormFields.get(matches("^.*_link$"))).thenReturn(new LinkFieldProperty());
82
+ when(mockFormFields.get(matches("^.*_file$"))).thenReturn(new FileFieldProperty());
83
+ when(mockFormFields.get(matches("^.*_subtable$"))).thenReturn(new SubtableFieldProperty());
84
+ AppClient mockAppClient = mock(AppClient.class);
85
+ when(mockAppClient.getFormFields(eq(0L))).thenReturn(mockFormFields);
86
+ GetRecordsByCursorResponseBody mockGetRecordsByCursorResponseBody =
87
+ mock(GetRecordsByCursorResponseBody.class);
88
+ when(mockGetRecordsByCursorResponseBody.getRecords()).thenReturn(records);
89
+ when(mockGetRecordsByCursorResponseBody.hasNext()).thenReturn(false);
90
+ when(mockRecordClient.createCursor(eq(0L), eq(fields), eq(query))).thenReturn("id");
91
+ when(mockRecordClient.getRecordsByCursor(eq("id")))
92
+ .thenReturn(mockGetRecordsByCursorResponseBody);
93
+ when(mockRecordClient.addRecords(eq(0L), anyList())).thenReturn(Collections.emptyList());
94
+ when(mockRecordClient.updateRecords(eq(0L), anyList())).thenReturn(Collections.emptyList());
95
+ com.kintone.client.KintoneClient mockKintoneClient = mock(KintoneClient.class);
96
+ when(mockKintoneClient.app()).thenReturn(mockAppClient);
97
+ when(mockKintoneClient.record()).thenReturn(mockRecordClient);
98
+ KintoneClientBuilder mockKintoneClientBuilder = mock(KintoneClientBuilder.class);
99
+ when(mockKintoneClientBuilder.authByApiToken(eq("token"))).thenReturn(mockKintoneClientBuilder);
100
+ when(mockKintoneClientBuilder.build()).thenReturn(mockKintoneClient);
101
+ try (MockedStatic<KintoneClientBuilder> mocked = mockStatic(KintoneClientBuilder.class)) {
102
+ mocked
103
+ .when(() -> KintoneClientBuilder.create(String.format("https://%s", domain)))
104
+ .thenReturn(mockKintoneClientBuilder);
105
+ runnable.run();
106
+ }
107
+ }
108
+
109
+ public interface Runnable {
110
+ void run() throws Exception;
111
+ }
112
+ }
@@ -1,5 +1,10 @@
1
1
  package org.embulk.output.kintone;
2
2
 
3
+ import static org.mockito.Mockito.inOrder;
4
+ import static org.mockito.Mockito.spy;
5
+ import static org.mockito.Mockito.verify;
6
+ import static org.mockito.Mockito.when;
7
+
3
8
  import com.google.common.io.Resources;
4
9
  import com.kintone.client.Json;
5
10
  import com.kintone.client.model.record.Record;
@@ -14,10 +19,17 @@ import java.util.Arrays;
14
19
  import java.util.Collections;
15
20
  import java.util.List;
16
21
  import java.util.Objects;
22
+ import java.util.Set;
23
+ import java.util.concurrent.atomic.AtomicReference;
17
24
  import java.util.function.Function;
18
25
  import java.util.stream.Collectors;
26
+ import org.embulk.config.ConfigDiff;
19
27
  import org.embulk.config.ConfigSource;
20
28
  import org.embulk.config.TaskSource;
29
+ import org.embulk.output.kintone.record.Id;
30
+ import org.embulk.output.kintone.record.Skip;
31
+ import org.embulk.spi.Column;
32
+ import org.embulk.spi.Exec;
21
33
  import org.embulk.spi.OutputPlugin;
22
34
  import org.embulk.spi.Schema;
23
35
  import org.embulk.spi.TransactionalPageOutput;
@@ -25,6 +37,7 @@ import org.embulk.spi.json.JsonParser;
25
37
  import org.embulk.test.EmbulkTests;
26
38
  import org.embulk.test.TestingEmbulk;
27
39
  import org.junit.Rule;
40
+ import org.mockito.InOrder;
28
41
  import org.msgpack.value.Value;
29
42
 
30
43
  public class TestKintoneOutputPlugin extends KintoneOutputPlugin {
@@ -36,20 +49,19 @@ public class TestKintoneOutputPlugin extends KintoneOutputPlugin {
36
49
  .registerPlugin(OutputPlugin.class, "kintone", TestKintoneOutputPlugin.class)
37
50
  .build();
38
51
 
52
+ @Override
53
+ public ConfigDiff transaction(
54
+ ConfigSource config, Schema schema, int taskCount, Control control) {
55
+ return config.get(String.class, "reduce_key", null) == null
56
+ ? super.transaction(config, schema, taskCount, control)
57
+ : transactionWithVerifier(config, schema, taskCount, control);
58
+ }
59
+
39
60
  @Override
40
61
  public TransactionalPageOutput open(TaskSource taskSource, Schema schema, int taskIndex) {
41
- String test = taskSource.get(String.class, "Domain");
42
- String mode = taskSource.get(String.class, "Mode");
43
- String field = taskSource.get(String.class, "UpdateKeyName");
44
- boolean preferNulls = taskSource.get(boolean.class, "PreferNulls");
45
- boolean ignoreNulls = taskSource.get(boolean.class, "IgnoreNulls");
46
- return new KintonePageOutputVerifier(
47
- super.open(taskSource, schema, taskIndex),
48
- test,
49
- field,
50
- getValues(test, preferNulls, ignoreNulls),
51
- getAddRecords(test, mode, preferNulls, ignoreNulls),
52
- getUpdateRecords(test, mode, preferNulls, ignoreNulls, field));
62
+ return taskSource.get(String.class, "ReduceKeyName") == null
63
+ ? openWithVerifier(taskSource, schema, taskIndex)
64
+ : super.open(taskSource, schema, taskIndex);
53
65
  }
54
66
 
55
67
  protected void runOutput(String configName, String inputName) throws Exception {
@@ -91,11 +103,105 @@ public class TestKintoneOutputPlugin extends KintoneOutputPlugin {
91
103
  return embulk.configLoader().fromYamlString(string);
92
104
  }
93
105
 
94
- private static List<String> getValues(String test, boolean preferNulls, boolean ignoreNulls) {
106
+ private ConfigDiff transactionWithVerifier(
107
+ ConfigSource config, Schema schema, int taskCount, Control control) {
108
+ try (KintonePageOutputVerifier verifier = verifier(config)) {
109
+ return runWithMock(verifier, config, schema, taskCount, control);
110
+ }
111
+ }
112
+
113
+ private ConfigDiff runWithMock(
114
+ KintonePageOutputVerifier verifier,
115
+ ConfigSource config,
116
+ Schema schema,
117
+ int taskCount,
118
+ OutputPlugin.Control control) {
119
+ String test = config.get(String.class, "domain");
120
+ PluginTask spyTask = spy(config.loadConfig(PluginTask.class));
121
+ ConfigSource spyConfig = spy(config);
122
+ when(spyConfig.loadConfig(PluginTask.class)).thenReturn(spyTask);
123
+ AtomicReference<ConfigDiff> configDiff = new AtomicReference<>();
124
+ verifier.runWithMock(
125
+ () -> configDiff.set(super.transaction(spyConfig, schema, taskCount, control)));
126
+ verify(spyConfig).loadConfig(PluginTask.class);
127
+ InOrder inOrderTask = inOrder(spyTask);
128
+ inOrderTask.verify(spyTask).setDerivedColumns(Collections.emptySet());
129
+ inOrderTask.verify(spyTask).setDerivedColumns(getDerivedColumns(test));
130
+ return configDiff.get();
131
+ }
132
+
133
+ private KintonePageOutputVerifier verifier(ConfigSource config) {
134
+ String test = config.get(String.class, "domain");
135
+ String mode = config.get(String.class, "mode");
136
+ String field = config.get(String.class, "update_key", null);
137
+ Skip skip = config.get(Skip.class, "skip_if_non_existing_id_or_update_key");
138
+ boolean preferNulls = config.get(boolean.class, "prefer_nulls", false);
139
+ boolean ignoreNulls = config.get(boolean.class, "ignore_nulls", false);
140
+ return new KintonePageOutputVerifier(
141
+ test,
142
+ field,
143
+ getValues(test, mode, skip, preferNulls, ignoreNulls, field),
144
+ getAddValues(test, mode, skip, preferNulls, ignoreNulls, field),
145
+ getAddRecords(test, mode, skip, preferNulls, ignoreNulls),
146
+ getUpdateRecords(test, mode, skip, preferNulls, ignoreNulls, field));
147
+ }
148
+
149
+ private TransactionalPageOutput openWithVerifier(
150
+ TaskSource taskSource, Schema schema, int taskIndex) {
151
+ String test = taskSource.get(String.class, "Domain");
152
+ String mode = taskSource.get(String.class, "Mode");
153
+ String field = taskSource.get(String.class, "UpdateKeyName");
154
+ Skip skip = taskSource.get(Skip.class, "SkipIfNonExistingIdOrUpdateKey");
155
+ boolean preferNulls = taskSource.get(boolean.class, "PreferNulls");
156
+ boolean ignoreNulls = taskSource.get(boolean.class, "IgnoreNulls");
157
+ return new KintonePageOutputVerifier(
158
+ super.open(taskSource, schema, taskIndex),
159
+ test,
160
+ field,
161
+ getValues(test, mode, skip, preferNulls, ignoreNulls, field),
162
+ getAddValues(test, mode, skip, preferNulls, ignoreNulls, field),
163
+ getAddRecords(test, mode, skip, preferNulls, ignoreNulls),
164
+ getUpdateRecords(test, mode, skip, preferNulls, ignoreNulls, field));
165
+ }
166
+
167
+ private static Set<Column> getDerivedColumns(String test) {
168
+ String name = String.format("%s/derived_columns.json", test);
169
+ String json = existsResource(name) ? readResource(name) : null;
170
+ return json == null || json.isEmpty()
171
+ ? Collections.emptySet()
172
+ : PARSER.parse(json).asArrayValue().list().stream()
173
+ .map(value -> Exec.getModelManager().readObject(Column.class, value.toJson()))
174
+ .collect(Collectors.toSet());
175
+ }
176
+
177
+ private static List<String> getValues(
178
+ String test, String mode, Skip skip, boolean preferNulls, boolean ignoreNulls, String field) {
179
+ String name =
180
+ String.format(
181
+ "%s/%s%s%s%s_values.json",
182
+ test,
183
+ mode,
184
+ format(skip),
185
+ ignoreNulls ? "_ignore_nulls" : preferNulls ? "_prefer_nulls" : "",
186
+ format(field));
187
+ String json = existsResource(name) ? readResource(name) : null;
188
+ return json == null || json.isEmpty()
189
+ ? Collections.emptyList()
190
+ : PARSER.parse(json).asArrayValue().list().stream()
191
+ .map(Value::toJson)
192
+ .collect(Collectors.toList());
193
+ }
194
+
195
+ private static List<String> getAddValues(
196
+ String test, String mode, Skip skip, boolean preferNulls, boolean ignoreNulls, String field) {
95
197
  String name =
96
198
  String.format(
97
- "%s/values%s.json",
98
- test, ignoreNulls ? "_ignore_nulls" : preferNulls ? "_prefer_nulls" : "");
199
+ "%s/%s%s%s%s_add_values.json",
200
+ test,
201
+ mode,
202
+ format(skip),
203
+ ignoreNulls ? "_ignore_nulls" : preferNulls ? "_prefer_nulls" : "",
204
+ format(field));
99
205
  String json = existsResource(name) ? readResource(name) : null;
100
206
  return json == null || json.isEmpty()
101
207
  ? Collections.emptyList()
@@ -105,11 +211,14 @@ public class TestKintoneOutputPlugin extends KintoneOutputPlugin {
105
211
  }
106
212
 
107
213
  private static List<Record> getAddRecords(
108
- String test, String mode, boolean preferNulls, boolean ignoreNulls) {
214
+ String test, String mode, Skip skip, boolean preferNulls, boolean ignoreNulls) {
109
215
  String name =
110
216
  String.format(
111
- "%s/%s_add%s_records.jsonl",
112
- test, mode, ignoreNulls ? "_ignore_nulls" : preferNulls ? "_prefer_nulls" : "");
217
+ "%s/%s%s%s_add_records.jsonl",
218
+ test,
219
+ mode,
220
+ format(skip),
221
+ ignoreNulls ? "_ignore_nulls" : preferNulls ? "_prefer_nulls" : "");
113
222
  String jsonl = existsResource(name) ? readResource(name) : null;
114
223
  return jsonl == null || jsonl.isEmpty()
115
224
  ? Collections.emptyList()
@@ -119,21 +228,37 @@ public class TestKintoneOutputPlugin extends KintoneOutputPlugin {
119
228
  }
120
229
 
121
230
  private static List<RecordForUpdate> getUpdateRecords(
122
- String test, String mode, boolean preferNulls, boolean ignoreNulls, String field) {
231
+ String test, String mode, Skip skip, boolean preferNulls, boolean ignoreNulls, String field) {
123
232
  Function<Record, UpdateKey> key = getKey(field);
233
+ Function<Record, RecordForUpdate> forUpdate =
234
+ record ->
235
+ Id.FIELD.equals(field)
236
+ ? new RecordForUpdate(record.getId(), Record.newFrom(record))
237
+ : new RecordForUpdate(key.apply(record), record.removeField(field));
124
238
  String name =
125
239
  String.format(
126
- "%s/%s_update%s_records.jsonl",
127
- test, mode, ignoreNulls ? "_ignore_nulls" : preferNulls ? "_prefer_nulls" : "");
240
+ "%s/%s%s%s_update_records.jsonl",
241
+ test,
242
+ mode,
243
+ format(skip),
244
+ ignoreNulls ? "_ignore_nulls" : preferNulls ? "_prefer_nulls" : "");
128
245
  String jsonl = existsResource(name) ? readResource(name) : null;
129
246
  return jsonl == null || jsonl.isEmpty()
130
247
  ? Collections.emptyList()
131
248
  : Arrays.stream(jsonl.split("\\r?\\n|\\r"))
132
249
  .map(s -> Json.parse(s, Record.class))
133
- .map(record -> new RecordForUpdate(key.apply(record), record.removeField(field)))
250
+ .map(forUpdate)
134
251
  .collect(Collectors.toList());
135
252
  }
136
253
 
254
+ private static String format(Skip skip) {
255
+ return skip == Skip.AUTO ? "" : String.format("_%s_skip", skip.name().toLowerCase());
256
+ }
257
+
258
+ private static String format(String string) {
259
+ return string == null ? "" : String.format("_%s", string.replace('$', '_'));
260
+ }
261
+
137
262
  private static Function<Record, UpdateKey> getKey(String field) {
138
263
  return field == null
139
264
  ? record -> null
@@ -34,6 +34,7 @@ public class TestTaskMode extends TestTask {
34
34
  @Test
35
35
  public void testUpsert() throws Exception {
36
36
  merge(config("mode: upsert", "update_key: double_single_line_text"));
37
+ merge(config("skip_if_non_existing_id_or_update_key: never"));
37
38
  runOutput();
38
39
  merge(config("prefer_nulls: true"));
39
40
  runOutput();