diff --git a/2026-01/spring-24-spring-batch/.gitignore b/2026-01/spring-24-spring-batch/.gitignore new file mode 100644 index 00000000..7622f151 --- /dev/null +++ b/2026-01/spring-24-spring-batch/.gitignore @@ -0,0 +1,9 @@ +.idea/ +*.iml + +target/ + +output.csv +*.log +output*.dat +test-output.dat diff --git a/2026-01/spring-24-spring-batch/entries.csv b/2026-01/spring-24-spring-batch/entries.csv new file mode 100644 index 00000000..bde433ce --- /dev/null +++ b/2026-01/spring-24-spring-batch/entries.csv @@ -0,0 +1,16 @@ +Ivan,23 +John,24 +Ivan,23 +John,24 +Ivan,23 +Mary,24 +Ivan,23 +John,24 +Sunny,23 +John,24 +Ivan,23 +John,24 +Ivan,23 +John,24 +Ivan,23 +John,24 diff --git a/2026-01/spring-24-spring-batch/pom.xml b/2026-01/spring-24-spring-batch/pom.xml new file mode 100644 index 00000000..7e088c99 --- /dev/null +++ b/2026-01/spring-24-spring-batch/pom.xml @@ -0,0 +1,131 @@ + + + 4.0.0 + + ru.otus.example + spring-batch-demo + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + + 3.5.6 + + + + + 17 + 17 + 17 + 4.3.8 + 4.11.0 + 2.2.220 + 2.0 + 32.1.2-jre + + + + + + org.springframework.boot + spring-boot-starter-batch + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + + com.h2database + h2 + runtime + ${h2.version} + + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + ${flapdoodle.version} + + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo.spring30x + ${flapdoodle.version} + + + + com.github.cloudyrock.mongock + mongock-spring-v5 + ${mongock.version} + + + com.google.guava + guava + + + + + + com.google.guava + guava + ${guava.version} + + + + com.github.cloudyrock.mongock + mongodb-springdata-v3-driver + ${mongock.version} + + + + org.projectlombok + lombok + true + + + + org.springframework.shell + spring-shell-starter + 3.4.0 + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.batch + spring-batch-test + test + + + + + spring-batch-demo + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/Main.java b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/Main.java new file mode 100644 index 00000000..58b6edf6 --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/Main.java @@ -0,0 +1,16 @@ +package ru.otus.example.springbatch; + +import com.github.cloudyrock.spring.v5.EnableMongock; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@EnableMongock +@SpringBootApplication +public class Main { + // --spring.shell.interactive.enabled=false --spring.batch.job.enabled=true inputFileName=entries.csv outputFileName=output_new.dat + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } +} + + diff --git a/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/chandgelogs/InitMongoDBDataChangeLog.java b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/chandgelogs/InitMongoDBDataChangeLog.java new file mode 100644 index 00000000..feb52399 --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/chandgelogs/InitMongoDBDataChangeLog.java @@ -0,0 +1,45 @@ +package ru.otus.example.springbatch.chandgelogs; + +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; +import com.github.cloudyrock.mongock.driver.mongodb.springdata.v3.decorator.impl.MongockTemplate; +import com.mongodb.client.MongoDatabase; +import ru.otus.example.springbatch.model.Person; + +@ChangeLog(order = "001") +public class InitMongoDBDataChangeLog { + + @ChangeSet(order = "000", id = "dropDB", author = "stvort", runAlways = true) + public void dropDB(MongoDatabase database){ + database.drop(); + } + + @ChangeSet(order = "001", id = "initPersons", author = "stvort", runAlways = true) + public void initPersons(MongockTemplate template){ + template.save(new Person("Джон", 21)); + template.save(new Person("Игорь", 32)); + template.save(new Person("Дмитрий", 52)); + template.save(new Person("Михаил", 22)); + template.save(new Person("Герман", 33)); + template.save(new Person("Джон", 21)); + template.save(new Person("Игорь", 32)); + template.save(new Person("Дмитрий", 52)); + template.save(new Person("Михаил", 22)); + template.save(new Person("Герман", 33)); + template.save(new Person("Джон", 21)); + template.save(new Person("Игорь", 32)); + template.save(new Person("Дмитрий", 52)); + template.save(new Person("Михаил", 22)); + template.save(new Person("Герман", 33)); + template.save(new Person("Джон", 21)); + template.save(new Person("Игорь", 32)); + template.save(new Person("Дмитрий", 52)); + template.save(new Person("Михаил", 22)); + template.save(new Person("Герман", 33)); + template.save(new Person("Джон", 21)); + template.save(new Person("Игорь", 32)); + template.save(new Person("Дмитрий", 52)); + template.save(new Person("Михаил", 22)); + template.save(new Person("Герман", 33)); + } +} diff --git a/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/config/AppProps.java b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/config/AppProps.java new file mode 100644 index 00000000..5d9deb61 --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/config/AppProps.java @@ -0,0 +1,14 @@ +package ru.otus.example.springbatch.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties("app") +public class AppProps { + private String inputFile; + private String outputFile; + +} diff --git a/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/config/BatchConfig.java b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/config/BatchConfig.java new file mode 100644 index 00000000..276e92b9 --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/config/BatchConfig.java @@ -0,0 +1,17 @@ +package ru.otus.example.springbatch.config; + +import org.springframework.batch.core.configuration.JobRegistry; +import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@SuppressWarnings("unused") +//@Configuration +public class BatchConfig { + @Bean + public JobRegistryBeanPostProcessor postProcessor(JobRegistry jobRegistry) { + var processor = new JobRegistryBeanPostProcessor(); + processor.setJobRegistry(jobRegistry); + return processor; + } +} diff --git a/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/config/JobConfig.java b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/config/JobConfig.java new file mode 100644 index 00000000..2f1a81ed --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/config/JobConfig.java @@ -0,0 +1,188 @@ +package ru.otus.example.springbatch.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.core.*; +import org.springframework.batch.core.configuration.annotation.StepScope; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.launch.support.RunIdIncrementer; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.core.step.tasklet.MethodInvokingTaskletAdapter; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.file.FlatFileItemReader; +import org.springframework.batch.item.file.FlatFileItemWriter; +import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder; +import org.springframework.batch.item.file.builder.FlatFileItemWriterBuilder; +import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper; +import org.springframework.batch.item.file.transform.DelimitedLineAggregator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.FileSystemResource; +import org.springframework.lang.NonNull; +import org.springframework.transaction.PlatformTransactionManager; +import ru.otus.example.springbatch.model.Person; +import ru.otus.example.springbatch.service.CleanUpService; +import ru.otus.example.springbatch.service.HappyBirthdayService; + +import java.util.List; + + +@SuppressWarnings("unused") +@Configuration +public class JobConfig { + private static final int CHUNK_SIZE = 5; + private final Logger logger = LoggerFactory.getLogger("Batch"); + + public static final String OUTPUT_FILE_NAME = "outputFileName"; + public static final String INPUT_FILE_NAME = "inputFileName"; + public static final String IMPORT_USER_JOB_NAME = "importUserJob"; + + @Autowired + private JobRepository jobRepository; + + @Autowired + private PlatformTransactionManager platformTransactionManager; + + + @Autowired + private CleanUpService cleanUpService; + + @StepScope + @Bean + public FlatFileItemReader reader(@Value("#{jobParameters['" + INPUT_FILE_NAME + "']}") String inputFileName) { + return new FlatFileItemReaderBuilder() + .name("personItemReader") + .resource(new FileSystemResource(inputFileName)) + + .delimited() + .names("name", "age") + .fieldSetMapper(new BeanWrapperFieldSetMapper<>() {{ + setTargetType(Person.class); + }}).build(); + } + + @StepScope + @Bean + public ItemProcessor processor(HappyBirthdayService happyBirthdayService) { + return happyBirthdayService::doHappyBirthday; + } + + @StepScope + @Bean + public FlatFileItemWriter writer(@Value("#{jobParameters['" + OUTPUT_FILE_NAME + "']}") String outputFileName) { + return new FlatFileItemWriterBuilder() + .name("personItemWriter") + .resource(new FileSystemResource(outputFileName)) + .lineAggregator(new DelimitedLineAggregator<>()) + .build(); + } + + + @Bean + public MethodInvokingTaskletAdapter cleanUpTasklet() { + MethodInvokingTaskletAdapter adapter = new MethodInvokingTaskletAdapter(); + + adapter.setTargetObject(cleanUpService); + adapter.setTargetMethod("cleanUp"); + + return adapter; + } + + + @Bean + public Job importUserJob(Step transformPersonsStep, Step cleanUpStep) { + return new JobBuilder(IMPORT_USER_JOB_NAME, jobRepository) + .incrementer(new RunIdIncrementer()) + .flow(transformPersonsStep) + .next(cleanUpStep) + .end() + .listener(new JobExecutionListener() { + @Override + public void beforeJob(@NonNull JobExecution jobExecution) { + logger.info("Начало job"); + } + + @Override + public void afterJob(@NonNull JobExecution jobExecution) { + logger.info("Конец job"); + } + }) + .build(); + } + + @Bean + public Step transformPersonsStep(ItemReader reader, FlatFileItemWriter writer, + ItemProcessor itemProcessor) { + return new StepBuilder("transformPersonsStep", jobRepository) + .chunk(CHUNK_SIZE, platformTransactionManager) + .reader(reader) + .processor(itemProcessor) + .writer(writer) + .listener(new ItemReadListener<>() { + public void beforeRead() { + logger.info("Начало чтения"); + } + + public void afterRead(@NonNull Person o) { + logger.info("Конец чтения"); + } + + public void onReadError(@NonNull Exception e) { + logger.info("Ошибка чтения"); + } + }) + .listener(new ItemWriteListener() { + public void beforeWrite(@NonNull List list) { + logger.info("Начало записи"); + } + + public void afterWrite(@NonNull List list) { + logger.info("Конец записи"); + } + + public void onWriteError(@NonNull Exception e, @NonNull List list) { + logger.info("Ошибка записи"); + } + }) + .listener(new ItemProcessListener<>() { + public void beforeProcess(@NonNull Person o) { + logger.info("Начало обработки"); + } + + public void afterProcess(@NonNull Person o, Person o2) { + logger.info("Конец обработки"); + } + + public void onProcessError(@NonNull Person o, @NonNull Exception e) { + logger.info("Ошибка обработки"); + } + }) + .listener(new ChunkListener() { + public void beforeChunk(@NonNull ChunkContext chunkContext) { + logger.info("Начало пачки"); + } + + public void afterChunk(@NonNull ChunkContext chunkContext) { + logger.info("Конец пачки"); + } + + public void afterChunkError(@NonNull ChunkContext chunkContext) { + logger.info("Ошибка пачки"); + } + }) +// .taskExecutor(new SimpleAsyncTaskExecutor()) + .build(); + } + + @Bean + public Step cleanUpStep() { + return new StepBuilder("cleanUpStep", jobRepository) + .tasklet(cleanUpTasklet(), platformTransactionManager) + .build(); + } +} diff --git a/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/model/Person.java b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/model/Person.java new file mode 100644 index 00000000..b95cb1ff --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/model/Person.java @@ -0,0 +1,13 @@ +package ru.otus.example.springbatch.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@Data +public class Person { + private String name; + private int age; +} diff --git a/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/service/CleanUpService.java b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/service/CleanUpService.java new file mode 100644 index 00000000..9b88036d --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/service/CleanUpService.java @@ -0,0 +1,16 @@ +package ru.otus.example.springbatch.service; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class CleanUpService { + + @SuppressWarnings("unused") + public void cleanUp() throws Exception { + log.info("Выполняю завершающие мероприятия..."); + Thread.sleep(1000); + log.info("Завершающие мероприятия закончены"); + } +} diff --git a/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/service/HappyBirthdayService.java b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/service/HappyBirthdayService.java new file mode 100644 index 00000000..00ec7287 --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/service/HappyBirthdayService.java @@ -0,0 +1,13 @@ +package ru.otus.example.springbatch.service; + +import org.springframework.stereotype.Service; +import ru.otus.example.springbatch.model.Person; + +@Service +public class HappyBirthdayService { + + public Person doHappyBirthday(Person person){ + person.setAge(person.getAge() + 1); + return person; + } +} diff --git a/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/shell/BatchCommands.java b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/shell/BatchCommands.java new file mode 100644 index 00000000..a8f9db2c --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/main/java/ru/otus/example/springbatch/shell/BatchCommands.java @@ -0,0 +1,61 @@ +package ru.otus.example.springbatch.shell; + +import lombok.RequiredArgsConstructor; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.JobOperator; +import org.springframework.shell.standard.ShellComponent; +import org.springframework.shell.standard.ShellMethod; +import ru.otus.example.springbatch.config.AppProps; + +import java.util.Properties; + +import static ru.otus.example.springbatch.config.JobConfig.IMPORT_USER_JOB_NAME; +import static ru.otus.example.springbatch.config.JobConfig.INPUT_FILE_NAME; +import static ru.otus.example.springbatch.config.JobConfig.OUTPUT_FILE_NAME; + +@RequiredArgsConstructor +@ShellComponent +public class BatchCommands { + + private final AppProps appProps; + private final Job importUserJob; + + private final JobLauncher jobLauncher; + private final JobOperator jobOperator; + private final JobExplorer jobExplorer; + + //http://localhost:8080/h2-console/ + + + @SuppressWarnings("unused") + @ShellMethod(value = "startMigrationJobWithJobLauncher", key = "sm-jl") + public void startMigrationJobWithJobLauncher() throws Exception { + JobExecution execution = jobLauncher.run(importUserJob, new JobParametersBuilder() + .addString(INPUT_FILE_NAME, appProps.getInputFile()) + .addString(OUTPUT_FILE_NAME, appProps.getOutputFile()) + .toJobParameters()); + System.out.println(execution); + } + + @SuppressWarnings("unused") + @ShellMethod(value = "startMigrationJobWithJobOperator", key = "sm-jo") + public void startMigrationJobWithJobOperator() throws Exception { + Properties properties = new Properties(); + properties.put(INPUT_FILE_NAME, appProps.getInputFile()); + properties.put(OUTPUT_FILE_NAME, appProps.getOutputFile()); + + Long executionId = jobOperator.start(IMPORT_USER_JOB_NAME, properties); + System.out.println(jobOperator.getSummary(executionId)); + } + + @SuppressWarnings("unused") + @ShellMethod(value = "showInfo", key = "i") + public void showInfo() { + System.out.println(jobExplorer.getJobNames()); + System.out.println(jobExplorer.getLastJobInstance(IMPORT_USER_JOB_NAME)); + } +} diff --git a/2026-01/spring-24-spring-batch/src/main/resources/application.yml b/2026-01/spring-24-spring-batch/src/main/resources/application.yml new file mode 100644 index 00000000..2c5a9894 --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/main/resources/application.yml @@ -0,0 +1,60 @@ +spring: + main: + allow-circular-references: true + + batch: + job: + enabled: false + + shell: + interactive: + enabled: true + noninteractive: + enabled: false + + command: + version: + enabled: false + + data: + mongodb: + host: localhost + port: 0 + database: SpringBatchExampleDB + + datasource: + url: jdbc:h2:mem:testdb + driverClassName: org.h2.Driver + username: sa + password: + + h2: + console: + enabled: true + path: /h2-console +de: + flapdoodle: + mongodb: + embedded: + version: 6.0.5 + +mongock: + runner-type: "InitializingBean" + change-logs-scan-package: + - ru.otus.example.springbatch.chandgelogs + mongo-db: + write-concern: + journal: false + read-concern: local + +app: + ages-count-to-add: 1 + input-file: entries.csv + output-file: output.dat + +logging: + level: + root: ERROR + Batch: INFO + ru.otus.example.springbatch: INFO + diff --git a/2026-01/spring-24-spring-batch/src/test/java/ru/otus/example/springbatch/config/ImportUserJobTest.java b/2026-01/spring-24-spring-batch/src/test/java/ru/otus/example/springbatch/config/ImportUserJobTest.java new file mode 100644 index 00000000..3a4441bf --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/test/java/ru/otus/example/springbatch/config/ImportUserJobTest.java @@ -0,0 +1,72 @@ +package ru.otus.example.springbatch.config; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.batch.test.JobRepositoryTestUtils; +import org.springframework.batch.test.context.SpringBatchTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.io.File; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +import static org.assertj.core.api.Assertions.assertThat; +import static ru.otus.example.springbatch.config.JobConfig.IMPORT_USER_JOB_NAME; +import static ru.otus.example.springbatch.config.JobConfig.INPUT_FILE_NAME; +import static ru.otus.example.springbatch.config.JobConfig.OUTPUT_FILE_NAME; + +@SpringBootTest +@SpringBatchTest +class ImportUserJobTest { + + private static final String TEST_INPUT_FILE_NAME = "test-entries.csv"; + private static final String EXPECTED_OUTPUT_FILE_NAME = "expected-test-output.dat"; + private static final String EXPECTED_MONGO_OUTPUT_FILE_NAME = "expected-mongo-test-output.dat"; + private static final String TEST_OUTPUT_FILE_NAME = "test-output.dat"; + + @Autowired + private JobLauncherTestUtils jobLauncherTestUtils; + + @Autowired + private JobRepositoryTestUtils jobRepositoryTestUtils; + + @BeforeEach + void clearMetaData() { + jobRepositoryTestUtils.removeJobExecutions(); + } + + @Test + void testJob() throws Exception { + var classLoader = ImportUserJobTest.class.getClassLoader(); + var testInputFileName = URLDecoder.decode( + Objects.requireNonNull(classLoader.getResource(TEST_INPUT_FILE_NAME)).getFile(), + StandardCharsets.UTF_8 + ); + var expectedResultFileName = URLDecoder.decode( + Objects.requireNonNull(classLoader.getResource(EXPECTED_OUTPUT_FILE_NAME)).getFile(), + StandardCharsets.UTF_8 + ); + + Job job = jobLauncherTestUtils.getJob(); + assertThat(job).isNotNull() + .extracting(Job::getName) + .isEqualTo(IMPORT_USER_JOB_NAME); + + JobParameters parameters = new JobParametersBuilder() + .addString(INPUT_FILE_NAME, testInputFileName) + .addString(OUTPUT_FILE_NAME, TEST_OUTPUT_FILE_NAME) + .toJobParameters(); + JobExecution jobExecution = jobLauncherTestUtils.launchJob(parameters); + + assertThat(jobExecution.getExitStatus().getExitCode()).isEqualTo("COMPLETED"); + assertThat(new File(TEST_OUTPUT_FILE_NAME)) + .hasSameTextualContentAs(new File(expectedResultFileName), StandardCharsets.UTF_8); + } +} \ No newline at end of file diff --git a/2026-01/spring-24-spring-batch/src/test/java/ru/otus/example/springbatch/testchangelogs/InitMongoDBDataChangeLog.java b/2026-01/spring-24-spring-batch/src/test/java/ru/otus/example/springbatch/testchangelogs/InitMongoDBDataChangeLog.java new file mode 100644 index 00000000..bacb4ee2 --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/test/java/ru/otus/example/springbatch/testchangelogs/InitMongoDBDataChangeLog.java @@ -0,0 +1,45 @@ +package ru.otus.example.springbatch.testchangelogs; + +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; +import com.github.cloudyrock.mongock.driver.mongodb.springdata.v3.decorator.impl.MongockTemplate; +import com.mongodb.client.MongoDatabase; +import ru.otus.example.springbatch.model.Person; + +@ChangeLog(order = "001") +public class InitMongoDBDataChangeLog { + + @ChangeSet(order = "000", id = "dropDB", author = "stvort", runAlways = true) + public void dropDB(MongoDatabase database){ + database.drop(); + } + + @ChangeSet(order = "001", id = "initPersons", author = "stvort", runAlways = true) + public void initPersons(MongockTemplate template){ + template.save(new Person("Тестовый Джон", 21)); + template.save(new Person("Тестовый Игорь", 32)); + template.save(new Person("Тестовый Дмитрий", 52)); + template.save(new Person("Тестовый Михаил", 22)); + template.save(new Person("Тестовый Герман", 33)); + template.save(new Person("Тестовый Джон", 21)); + template.save(new Person("Тестовый Игорь", 32)); + template.save(new Person("Тестовый Дмитрий", 52)); + template.save(new Person("Тестовый Михаил", 22)); + template.save(new Person("Тестовый Герман", 33)); + template.save(new Person("Тестовый Джон", 21)); + template.save(new Person("Тестовый Игорь", 32)); + template.save(new Person("Тестовый Дмитрий", 52)); + template.save(new Person("Тестовый Михаил", 22)); + template.save(new Person("Тестовый Герман", 33)); + template.save(new Person("Тестовый Джон", 21)); + template.save(new Person("Тестовый Игорь", 32)); + template.save(new Person("Тестовый Дмитрий", 52)); + template.save(new Person("Тестовый Михаил", 22)); + template.save(new Person("Тестовый Герман", 33)); + template.save(new Person("Тестовый Джон", 21)); + template.save(new Person("Тестовый Игорь", 32)); + template.save(new Person("Тестовый Дмитрий", 52)); + template.save(new Person("Тестовый Михаил", 22)); + template.save(new Person("Тестовый Герман", 33)); + } +} diff --git a/2026-01/spring-24-spring-batch/src/test/resources/application.yml b/2026-01/spring-24-spring-batch/src/test/resources/application.yml new file mode 100644 index 00000000..0f1636bc --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/test/resources/application.yml @@ -0,0 +1,43 @@ +spring: + main: + allow-circular-references: true + + batch: + job: + enabled: false + + shell: + interactive: + enabled: false + command: + version: + enabled: false + + datasource: + url: jdbc:h2:mem:testdb + driverClassName: org.h2.Driver + username: sa + password: + + + + data: + mongodb: + host: localhost + port: 0 + database: SpringBatchTestExampleDB + +de: + flapdoodle: + mongodb: + embedded: + version: 6.0.5 + +mongock: + runner-type: "InitializingBean" + change-logs-scan-package: + - ru.otus.example.springbatch.testchangelogs + mongo-db: + write-concern: + journal: false + read-concern: local \ No newline at end of file diff --git a/2026-01/spring-24-spring-batch/src/test/resources/expected-mongo-test-output.dat b/2026-01/spring-24-spring-batch/src/test/resources/expected-mongo-test-output.dat new file mode 100644 index 00000000..3f35d174 --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/test/resources/expected-mongo-test-output.dat @@ -0,0 +1,25 @@ +Person(name=Тестовый Дмитрий, age=53) +Person(name=Тестовый Дмитрий, age=53) +Person(name=Тестовый Дмитрий, age=53) +Person(name=Тестовый Дмитрий, age=53) +Person(name=Тестовый Дмитрий, age=53) +Person(name=Тестовый Герман, age=34) +Person(name=Тестовый Герман, age=34) +Person(name=Тестовый Герман, age=34) +Person(name=Тестовый Герман, age=34) +Person(name=Тестовый Герман, age=34) +Person(name=Тестовый Игорь, age=33) +Person(name=Тестовый Игорь, age=33) +Person(name=Тестовый Игорь, age=33) +Person(name=Тестовый Игорь, age=33) +Person(name=Тестовый Игорь, age=33) +Person(name=Тестовый Михаил, age=23) +Person(name=Тестовый Михаил, age=23) +Person(name=Тестовый Михаил, age=23) +Person(name=Тестовый Михаил, age=23) +Person(name=Тестовый Михаил, age=23) +Person(name=Тестовый Джон, age=22) +Person(name=Тестовый Джон, age=22) +Person(name=Тестовый Джон, age=22) +Person(name=Тестовый Джон, age=22) +Person(name=Тестовый Джон, age=22) diff --git a/2026-01/spring-24-spring-batch/src/test/resources/expected-test-output.dat b/2026-01/spring-24-spring-batch/src/test/resources/expected-test-output.dat new file mode 100644 index 00000000..b4c926b1 --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/test/resources/expected-test-output.dat @@ -0,0 +1,16 @@ +Person(name=Ivan, age=24) +Person(name=John, age=25) +Person(name=Ivan, age=24) +Person(name=John, age=25) +Person(name=Ivan, age=24) +Person(name=Mary, age=25) +Person(name=Ivan, age=24) +Person(name=John, age=25) +Person(name=Sunny, age=24) +Person(name=John, age=25) +Person(name=Ivan, age=24) +Person(name=John, age=25) +Person(name=Ivan, age=24) +Person(name=John, age=25) +Person(name=Ivan, age=24) +Person(name=John, age=25) diff --git a/2026-01/spring-24-spring-batch/src/test/resources/test-entries.csv b/2026-01/spring-24-spring-batch/src/test/resources/test-entries.csv new file mode 100644 index 00000000..bde433ce --- /dev/null +++ b/2026-01/spring-24-spring-batch/src/test/resources/test-entries.csv @@ -0,0 +1,16 @@ +Ivan,23 +John,24 +Ivan,23 +John,24 +Ivan,23 +Mary,24 +Ivan,23 +John,24 +Sunny,23 +John,24 +Ivan,23 +John,24 +Ivan,23 +John,24 +Ivan,23 +John,24