Салом ба ҳама. Ба шумо хотиррасон мекунам: дар қисми аввал мо Flyway-ро илова кардем. Биёед идома диҳем.
Илова кардани пойгоҳи додаҳо ба docker-compose.yml
Марҳилаи навбатӣ насб кардани кор бо пойгоҳи додаҳо дар docker-compose.yml мебошад. Биёед базаро ба файли docker-compose илова кунем:version: '3.1'
services:
jrtb-bot:
depends_on:
- jrtb-db
build:
context: .
environment:
BOT_NAME: ${BOT_NAME}
BOT_TOKEN: ${BOT_TOKEN}
BOT_DB_USERNAME: ${BOT_DB_USERNAME}
BOT_DB_PASSWORD: ${BOT_DB_PASSWORD}
restart: always
jrtb-db:
image: mysql:5.7
restart: always
environment:
MYSQL_USER: ${BOT_DB_USERNAME}
MYSQL_PASSWORD: ${BOT_DB_PASSWORD}
MYSQL_DATABASE: 'jrtb_db'
MYSQL_ROOT_PASSWORD: 'root'
ports:
- '3306:3306'
expose:
- '3306'
Ман инчунин ин сатрро ба аризаи худ илова кардам:
depends_on:
- jrtb-db
Ин маънои онро дорад, ки мо пеш аз оғози барнома интизорем, ки пойгоҳи додаҳо оғоз шавад. Баъдан, шумо метавонед илова кардани ду тағирёбандаи дигарро мушоҳида кунед, ки мо бояд бо пойгоҳи додаҳо кор кунем:
${BOT_DB_USERNAME}
${BOT_DB_PASSWORD}
Мо онҳоро дар docker-compose ба мисли боти телеграмма - тавассути тағирёбандаҳои муҳити зист мегирем. Ман ин корро кардам, то ки мо танҳо як ҷое дошта бошем, ки мо арзишҳои номи корбари пойгоҳи додаҳо ва пароли онро муқаррар кунем. Мо онҳоро ба тасвири докери замимаи худ ва ба контейнери докери пойгоҳи додаамон мерасонем. Минбаъд мо бояд файли Docker-ро навсозӣ кунем, то ба SpringBoot-и худ қабули тағирёбандаҳоро барои пойгоҳи додаҳо омӯзем.
FROM adoptopenjdk/openjdk11:ubi
ARG JAR_FILE=target/*.jar
ENV BOT_NAME=test.javarush_community_bot
ENV BOT_TOKEN=1375780501:AAE4A6Rz0BSnIGzeu896OjQnjzsMEG6_uso
ENV BOT_DB_USERNAME=jrtb_db_user
ENV BOT_DB_PASSWORD=jrtb_db_password
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Dspring.datasource.password=${BOT_DB_PASSWORD}", "-Dbot.username=${BOT_NAME}", "-Dbot.token=${BOT_TOKEN}", "-Dspring.datasource.username=${BOT_DB_USERNAME}", "-jar", "app.jar"]
Ҳоло мо тағирёбандаҳои пойгоҳи додаҳоро ба Dockerfile илова мекунем:
ENV BOT_DB_USERNAME=jrtb_db_user
ENV BOT_DB_PASSWORD=jrtb_db_password
Арзишҳои тағирёбанда гуногун хоҳанд буд. Онҳое, ки мо ба Dockerfile мегузарем, арзишҳои пешфарзро талаб мекунанд, бинобар ин ман баъзеро ворид кардам. Мо сатри охиринро бо ду унсур васеъ мекунем, ки бо ёрии онҳо номи корбар ва пароли DB-ро ба оғози барнома мегузорем:
"-Dspring.datasource.password=${BOT_DB_PASSWORD}", "-Dbot.username=${BOT_NAME}"
Сатри охирин дар файли Docker (ки бо ENTRYPOINT оғоз мешавад) бояд бидуни печондан бошад. Агар шумо интиқол диҳед, ин code кор намекунад. Қадами охирин ин навсозии файли start.sh барои интиқол додани тағирёбандаҳо ба пойгоҳи додаҳо мебошад.
#!/bin/bash
# Pull new changes
git pull
# Prepare Jar
mvn clean
mvn package
# Ensure, that docker-compose stopped
docker-compose stop
# Add environment variables
export BOT_NAME=$1
export BOT_TOKEN=$2
export BOT_DB_USERNAME='prod_jrtb_db_user'
export BOT_DB_PASSWORD='Pap9L9VVUkNYj99GCUCC3mJkb'
# Start new deployment
docker-compose up --build -d
Мо аллакай медонем, ки чӣ гуна пеш аз иҷро кардани docker-compose тағирёбандаҳои муҳити атрофро илова кунем. Барои ин ба шумо лозим аст, ки содироти var_name=var_value -ро иҷро кунед. Аз ин рӯ, мо танҳо ду сатр илова мекунем:
export BOT_DB_USERNAME='prod_jrtb_db_user'
export BOT_DB_PASSWORD='Pap9L9VVUkNYj99GCUCC3mJkb'
Дар ин ҷо мо номи корбар ва пароли пойгоҳи додаҳоро муқаррар мекунем. Албатта, ин тағирёбандаҳоро ҳангоми иҷро кардани скрипти bash метавон интиқол дод, чуноне ки мо барои ном ва аломати бот мекунем. Аммо ба назарам ин нодаркор аст. Барои воқеан дастрасӣ ба пойгоҳи додаҳо, шумо бояд IP-и serverеро, ки дар он пойгоҳи додаҳо ҷойгир карда мешавад, бидонед ва дар рӯйхати суроғаҳои IP-и иҷозатдодашудаи дархост бошед. Ба ман бошад, ин аллакай кифоя аст. Асос гузошта шудааст: акнун шумо метавонед корҳоеро иҷро кунед, ки барои таҳиягар фаҳмотаранд - code нависед. Пеш аз он, мо кореро мекардем, ки муҳандисони DevOps мекунанд - эҷод кардани муҳити зист.
Илова кардани қабати репозиторий
Одатан барнома се қабат дорад:- Назоратчиён нуқтаҳои воридшавӣ ба барнома мебошанд.
- Хидматҳо дар он ҷое ҳастанд, ки мантиқи тиҷорат кор мекунад. Мо аллакай қисман инро дорем: SendMessageService намояндаи возеҳи мантиқи тиҷорат аст.
- Анборҳо ҷои кор бо пойгоҳи додаҳо мебошанд. Дар ҳолати мо, ин боти телеграмма аст.
- Мо набояд бо JDBC кор кунем: мо мустақиман бо абстраксияҳои баландтар кор хоҳем кард. Яъне, POJO-ҳоро, ки ба ҷадвалҳо дар пойгоҳи додаҳо мувофиқанд, нигоҳ доред. Мо чунин синфҳоро an object номида мешавем , зеро онҳо расман дар Java Persistence API номида мешаванд (ин маҷмӯи маъмули интерфейсҳо барои кор бо пойгоҳи додаҳо тавассути ORM мебошад, яъне абстраксияи кор бо JDBC). Мо синфи an objectе хоҳем дошт, ки мо онро дар базаи маълумот захира мекунем ва онҳо маҳз ба ҷадвале, ки ба мо лозим аст, навишта мешаванд. Ҳангоми ҷустуҷӯ дар пойгоҳи додаҳо мо ҳамон an objectҳоро мегирем.
- Spring Data барои истифодаи маҷмӯи интерфейсҳои онҳо пешниҳод мекунад: JpaRepository , CrudRepository , ва ғайра... Интерфейсҳои дигар вуҷуд доранд: рӯйхати пурраро дар ин ҷо пайдо кардан мумкин аст . Зебоӣ дар он аст, ки шумо метавонед усулҳои онҳоро бидуни татбиқи онҳо истифода баред(!). Ғайр аз он, як қолаби муайяне мавҷуд аст, ки тавассути он шумо метавонед дар интерфейс усулҳои нав нависед ва онҳо ба таври худкор амалӣ карда мешаванд.
- Бахор тараккиёти моро ба кадри имкон осон мекунад. Барои ин, мо бояд интерфейси худро эҷод кунем ва аз онҳое, ки дар боло тавсиф шудаанд, мерос гирем. Ва то баҳор донад, ки вай бояд ин интерфейсро истифода барад, шарҳи анборро илова кунед.
- Агар ба мо лозим ояд, ки усули кор бо пойгоҳи додаҳо вуҷуд надошта бошад, пас ин ҳам мушкил нест - мо онро менависем. Ман ба шумо нишон медиҳам, ки дар он ҷо чӣ кор кардан лозим аст.
package com.github.javarushcommunity.jrtb.repository.entity;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
/**
* Telegram User entity.
*/
@Data
@Entity
@Table(name = "tg_user")
public class TelegramUser {
@Id
@Column(name = "chat_id")
private String chatId;
@Column(name = "active")
private boolean active;
}
Дар ин ҷо шумо мебинед, ки мо ҳама эзоҳҳоро аз бастаи javax.persistence дорем. Инҳо шарҳҳои умумӣ мебошанд, ки барои ҳама татбиқи ORM истифода мешаванд. Бо нобаёнӣ, Spring Data Jpa Hibernate-ро истифода мебарад, гарчанде ки дигар татбиқҳо метавонанд истифода шаванд. Ин аст рӯйхати эзоҳҳое, ки мо истифода мебарем:
- Объект - нишон медиҳад, ки ин an object барои кор бо пойгоҳи додаҳо мебошад;
- Ҷадвал – дар ин ҷо номи ҷадвалро муайян мекунем;
- Id - эзоҳ мегӯяд, ки кадом соҳа дар ҷадвал Калиди ибтидоӣ хоҳад буд;
- Сутун - номи майдонро аз ҷадвал муайян кунед.
package com.github.javarushcommunity.jrtb.repository;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* {@link Repository} for handling with {@link TelegramUser} entity.
*/
@Repository
public interface TelegramUserRepository extends JpaRepository<TelegramUser, String> {
List<TelegramUser> findAllByActiveTrue();
}
Дар ин ҷо шумо мебинед, ки чӣ тавр ман усули findAllByActiveTrue() -ро илова кардам , ки ман онро дар ҳеҷ ҷо татбиқ намекунам. Аммо ин ба кори вай халал намерасонад. Маълумоти баҳорӣ мефаҳмад, ки он бояд ҳамаи сабтҳоро аз ҷадвали tg_user гирад, ки майдони фаъоли он = true . Мо хидматеро барои кор бо субъекти TelegramUser илова мекунем (мо инversionи вобастагӣ аз SOLID-ро дар шароите истифода мебарем, ки хидматҳои дигар an objectҳо наметавонанд мустақиман бо репозиторийии шахси дигар иртибот дошта бошанд - танҳо тавассути хидмати ин муассиса). Мо дар баста хидматрасонии TelegramUserService эҷод мекунем, ки ҳоло он якчанд усул дорад: корбарро захира кунед, корбарро бо ID-и худ гиред ва рӯйхати корбарони фаъолро намоиш диҳед. Аввал мо интерфейси TelegramUserService-ро эҷод мекунем:
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* {@link Service} for handling {@link TelegramUser} entity.
*/
public interface TelegramUserService {
/**
* Save provided {@link TelegramUser} entity.
*
* @param telegramUser provided telegram user.
*/
void save(TelegramUser telegramUser);
/**
* Retrieve all active {@link TelegramUser}.
*
* @return the collection of the active {@link TelegramUser} objects.
*/
List<TelegramUser> retrieveAllActiveUsers();
/**
* Find {@link TelegramUser} by chatId.
*
* @param chatId provided Chat ID
* @return {@link TelegramUser} with provided chat ID or null otherwise.
*/
Optional<TelegramUser> findByChatId(String chatId);
}
Ва, дар асл, татбиқи TelegramUserServiceImpl:
package com.github.javarushcommunity.jrtb.service;
import com.github.javarushcommunity.jrtb.repository.TelegramUserRepository;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
/**
* Implementation of {@link TelegramUserService}.
*/
@Service
public class TelegramUserServiceImpl implements TelegramUserService {
private final TelegramUserRepository telegramUserRepository;
@Autowired
public TelegramUserServiceImpl(TelegramUserRepository telegramUserRepository) {
this.telegramUserRepository = telegramUserRepository;
}
@Override
public void save(TelegramUser telegramUser) {
telegramUserRepository.save(telegramUser);
}
@Override
public List<TelegramUser> retrieveAllActiveUsers() {
return telegramUserRepository.findAllByActiveTrue();
}
@Override
public Optional<TelegramUser> findByChatId(String chatId) {
return telegramUserRepository.findById(chatId);
}
}
Дар ин ҷо бояд қайд кард, ки мо тазриқи вобастагӣ (ҷори як мисоли синф) -и an objectи TelegramuserRepository -ро бо истифода аз шарҳи Autowired ва конструктор истифода мебарем. Шумо метавонед ин корро барои тағирёбанда иҷро кунед, аммо ин равишест, ки гурӯҳи Spring Framework ба мо тавсия медиҳад.
Илова кардани омор барои бот
Минбаъд шумо бояд фармонҳои / start ва / stop -ро навсозӣ кунед. Вақте ки фармони /start истифода мешавад, шумо бояд корбари навро дар базаи маълумот захира кунед ва онро ба фаъол = true муқаррар кунед. Ва ҳангоме ки /stop мавҷуд аст, маълумоти корбарро навсозӣ кунед: фаъол = бардурӯғ муқаррар кунед. Биёед синфи StartCommand -ро ислоҳ кунем :package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.telegram.telegrambots.meta.api.objects.Update;
/**
* Start {@link Command}.
*/
public class StartCommand implements Command {
private final SendBotMessageService sendBotMessageService;
private final TelegramUserService telegramUserService;
public final static String START_MESSAGE = "Привет. Я Javarush Telegram Bot. Я помогу тебе быть в курсе последних " +
"статей тех авторов, котрые тебе интересны. Я еще маленький и только учусь.";
public StartCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
this.sendBotMessageService = sendBotMessageService;
this.telegramUserService = telegramUserService;
}
@Override
public void execute(Update update) {
String chatId = update.getMessage().getChatId().toString();
telegramUserService.findByChatId(chatId).ifPresentOrElse(
user -> {
user.setActive(true);
telegramUserService.save(user);
},
() -> {
TelegramUser telegramUser = new TelegramUser();
telegramUser.setActive(true);
telegramUser.setChatId(chatId);
telegramUserService.save(telegramUser);
});
sendBotMessageService.sendMessage(chatId, START_MESSAGE);
}
}
Дар ин ҷо мо инчунин an objectи TelegramuserService-ро ба конструктор мегузорем, ки бо он мо корбари навро захира мекунем. Ғайр аз он, бо истифода аз лаззатҳои Optional дар Java, мантиқи зерин кор мекунад: агар мо дар базаи маълумот корбар дошта бошем, мо ӯро танҳо фаъол мегардонем, агар не, мо як фаъоли нав эҷод мекунем. Фармони қатъ:
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.telegram.telegrambots.meta.api.objects.Update;
import java.util.Optional;
/**
* Stop {@link Command}.
*/
public class StopCommand implements Command {
private final SendBotMessageService sendBotMessageService;
private final TelegramUserService telegramUserService;
public static final String STOP_MESSAGE = "Деактивировал все ваши подписки \uD83D\uDE1F.";
public StopCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
this.sendBotMessageService = sendBotMessageService;
this.telegramUserService = telegramUserService;
}
@Override
public void execute(Update update) {
sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), STOP_MESSAGE);
telegramUserService.findByChatId(update.getMessage().getChatId().toString())
.ifPresent(it -> {
it.setActive(false);
telegramUserService.save(it);
});
}
}
Мо ҳамин тавр TelegramServiceTest-ро ба StopCommand мегузарем. Мантиқи иловагӣ ин аст: агар мо корбаре бо чунин ID чат дошта бошем, мо онро ғайрифаъол мекунем, яъне фаъол = бардурӯғ муқаррар мекунем. Чӣ тавр шумо инро бо чашмони худ мебинед? Биёед як фармони нави /stat эҷод кунем, ки омори ботро нишон медиҳад. Дар ин марҳила, инҳо омори оддӣ барои ҳамаи корбарон дастрас хоҳанд буд. Дар оянда, мо онро маҳдуд мекунем ва танҳо барои маъмурон дастрасӣ пайдо мекунем. Дар омор як сабт мавҷуд хоҳад буд: шумораи корбарони фаъоли бот. Барои ин, арзиши STAT("/stat") -ро ба CommandName илова кунед. Баъд, синфи StatCommand -ро эҷод кунед :
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.telegram.telegrambots.meta.api.objects.Update;
/**
* Statistics {@link Command}.
*/
public class StatCommand implements Command {
private final TelegramUserService telegramUserService;
private final SendBotMessageService sendBotMessageService;
public final static String STAT_MESSAGE = "Javarush Telegram Bot использует %s человек.";
@Autowired
public StatCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
this.sendBotMessageService = sendBotMessageService;
this.telegramUserService = telegramUserService;
}
@Override
public void execute(Update update) {
int activeUserCount = telegramUserService.retrieveAllActiveUsers().size();
sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), String.format(STAT_MESSAGE, activeUserCount));
}
}
Дар ин ҷо ҳама чиз оддӣ аст: мо рӯйхати ҳамаи корбарони фаъолро бо истифода аз усули retrieveAllActiveUsers мегирем ва андозаи коллексияро мегирем. Мо инчунин бояд ҳоло синфҳои болоравиро навсозӣ кунем: CommandContainer ва JavarushTelegramBot , то онҳо интиқоли хидмати наверо, ки ба мо лозим аст, ёд гиранд. Контейнери фармон:
package com.github.javarushcommunity.jrtb.command;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import com.google.common.collect.ImmutableMap;
import static com.github.javarushcommunity.jrtb.command.CommandName.*;
/**
* Container of the {@link Command}s, which are using for handling telegram commands.
*/
public class CommandContainer {
private final ImmutableMap<String, Command> commandMap;
private final Command unknownCommand;
public CommandContainer(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
commandMap = ImmutableMap.<String, Command>builder()
.put(START.getCommandName(), new StartCommand(sendBotMessageService, telegramUserService))
.put(STOP.getCommandName(), new StopCommand(sendBotMessageService, telegramUserService))
.put(HELP.getCommandName(), new HelpCommand(sendBotMessageService))
.put(NO.getCommandName(), new NoCommand(sendBotMessageService))
.put(STAT.getCommandName(), new StatCommand(sendBotMessageService, telegramUserService))
.build();
unknownCommand = new UnknownCommand(sendBotMessageService);
}
public Command retrieveCommand(String commandIdentifier) {
return commandMap.getOrDefault(commandIdentifier, unknownCommand);
}
}
Дар ин ҷо мо ба харита фармони нав илова кардем ва онро тавассути созандаи TelegramUserService гузаронидем. Аммо дар худи бот танҳо конструктор тағир меёбад:
@Autowired
public JavarushTelegramBot(TelegramUserService telegramUserService) {
this.commandContainer = new CommandContainer(new SendBotMessageServiceImpl(this), telegramUserService);
}
Ҳоло мо TelegramUserService-ро ҳамчун аргумент мегузорем ва илова кардани тавзеҳи Autowired. Ин маънои онро дорад, ки мо онро аз Контексти Ариза мегирем. Мо инчунин синфи HelpCommand- ро нав мекунем , то дар тавсиф фармони нави омор пайдо шавад.
Санҷиши дастӣ
Биёед пойгоҳи додаҳоро аз docker-compose-test.yml ва усули асосӣ дар синфи JavarushTelegramBotApplication оғоз кунем. Баъдан мо маҷмӯи фармонҳоро менависем:- / stat - мо интизорем, ки агар базаи маълумот холӣ бошад, ин ботро истифода мебарад, ки сифр нафар хоҳад буд;
- /start - оғоз кардани бот;
- /stat - ҳоло мо интизорем, ки бот аз ҷониби 1 нафар истифода мешавад;
- /сто - қатъ кардани бот;
- /stat - мо интизорем, ки боз 0 нафар аз он истифода хоҳанд кард.
Мо санҷишҳоро менависем ва навсозӣ мекунем
Азбаски мо конструкторҳоро иваз кардем, мо бояд синфҳои санҷиширо низ навсозӣ кунем. Дар синфи AbstractCommandTest , мо бояд як майдони дигарро илова кунем - синфи TelegramUserService , ки барои се фармон лозим аст:protected TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
Баъд, биёед усули init() -ро дар CommandContainer навсозӣ кунем :
@BeforeEach
public void init() {
SendBotMessageService sendBotMessageService = Mockito.mock(SendBotMessageService.class);
TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
commandContainer = new CommandContainer(sendBotMessageService, telegramUserService);
}
Дар StartCommand шумо бояд усули getCommand() -ро навсозӣ кунед :
@Override
Command getCommand() {
return new StartCommand(sendBotMessageService, telegramUserService);
}
Инчунин дар StopCommand:
@Override
Command getCommand() {
return new StopCommand(sendBotMessageService, telegramUserService);
}
Минбаъд биёед ба озмоишҳои нав назар кунем. Биёед озмоиши маъмулиро барои StatCommand эҷод кунем :
package com.github.javarushcommunity.jrtb.command;
import static com.github.javarushcommunity.jrtb.command.CommandName.STAT;
import static com.github.javarushcommunity.jrtb.command.StatCommand.STAT_MESSAGE;
public class StatCommandTest extends AbstractCommandTest {
@Override
String getCommandName() {
return STAT.getCommandName();
}
@Override
String getCommandMessage() {
return String.format(STAT_MESSAGE, 0);
}
@Override
Command getCommand() {
return new StatCommand(sendBotMessageService, telegramUserService);
}
}
Ин оддӣ аст. Акнун биёед дар бораи он сӯҳбат кунем, ки мо кор бо базаи маълумотро чӣ гуна озмоиш хоҳем кард. Мо ҳама чизеро, ки қаблан анҷом додем, санҷишҳои воҳидҳо буданд. Санҷиши ҳамгироӣ ҳамгироӣ байни қисмҳои зиёди барномаро месанҷад. Масалан, барномаҳо ва пойгоҳи додаҳо. Дар ин ҷо ҳама чиз мураккабтар хоҳад буд, зеро барои санҷиш ба мо базаи ҷойгиршуда лозим аст. Аз ин рӯ, вақте ки мо санҷишҳои худро ба таври маҳаллӣ иҷро мекунем, мо бояд пойгоҳи додаҳоро аз docker-compose-test.yml иҷро кунем. Барои иҷро кардани ин санҷиш, шумо бояд тамоми барномаи SpringBoot-ро иҷро кунед. Синфи санҷиш дорои шарҳи SpringBootTest мебошад , ки барномаро оғоз мекунад. Аммо ин равиш барои мо кор намекунад, зеро вақте ки барнома оғоз мешавад, боти телеграмма низ оғоз мешавад. Аммо дар ин ҷо ихтилоф вуҷуд дорад. Санҷишҳо ҳам ба таври маҳаллӣ дар мошини мо ва ҳам ба таври оммавӣ тавассути Actions GitHub гузаронида мешаванд. Барои он ки санҷишҳо бо оғози тамоми барнома гузаранд, мо бояд онҳоро бо маълумоти дуруст дар боти телеграмма иҷро кунем: яъне аз рӯи ном ва аломати он... Аз ин рӯ, мо ду интихоб дорем:
- Пас, ном ва нишони ботро оммавӣ кунед ва умедворед, ки ҳамааш хуб мешавад, касе аз он истифода намекунад ва ба мо халал намерасонад.
- Бо роҳи дигар биёед.
@Sql(scripts = {"/sql/clearDbs.sql", "/sql/telegram_users.sql"})
Барои мо, онҳо дар роҳи ./src/test/resources/ + роҳе, ки дар эзоҳ нишон дода шудааст, ҷойгир хоҳанд шуд. Ин аст, ки онҳо чӣ гунаанд:
clearDbs.sql:
DELETE FROM tg_user;
telegram_users.sql:
INSERT INTO tg_user VALUES ("123456789", 1);
INSERT INTO tg_user VALUES ("123456788", 1);
INSERT INTO tg_user VALUES ("123456787", 1);
INSERT INTO tg_user VALUES ("123456786", 1);
INSERT INTO tg_user VALUES ("123456785", 1);
INSERT INTO tg_user VALUES ("123456784", 0);
INSERT INTO tg_user VALUES ("123456782", 0);
INSERT INTO tg_user VALUES ("123456781", 0);
Дар натиҷа санҷиши TelegramUserRepositoryIT мо чунин хоҳад буд (чунон ки шумо мебинед, номи санҷиши ҳамгироӣ гуногун хоҳад буд - мо IT-ро илова мекунем, на Тест):
package com.github.javarushcommunity.jrtb.repository;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
import java.util.List;
import java.util.Optional;
import static org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace.NONE;
/**
* Integration-level testing for {@link TelegramUserRepository}.
*/
@ActiveProfiles("test")
@DataJpaTest
@AutoConfigureTestDatabase(replace = NONE)
public class TelegramUserRepositoryIT {
@Autowired
private TelegramUserRepository telegramUserRepository;
@Sql(scripts = {"/sql/clearDbs.sql", "/sql/telegram_users.sql"})
@Test
public void shouldProperlyFindAllActiveUsers() {
//when
List<TelegramUser> users = telegramUserRepository.findAllByActiveTrue();
//then
Assertions.assertEquals(5, users.size());
}
@Sql(scripts = {"/sql/clearDbs.sql"})
@Test
public void shouldProperlySaveTelegramUser() {
//given
TelegramUser telegramUser = new TelegramUser();
telegramUser.setChatId("1234567890");
telegramUser.setActive(false);
telegramUserRepository.save(telegramUser);
//when
Optional<TelegramUser> saved = telegramUserRepository.findById(telegramUser.getChatId());
//then
Assertions.assertTrue(saved.isPresent());
Assertions.assertEquals(telegramUser, saved.get());
}
}
Мо санҷишҳоро навиштем, аммо савол ба миён меояд: бо оғози раванди CI мо дар GitHub чӣ мешавад? Он пойгоҳи додаҳо нахоҳад дошт. Ҳоло дар ҳақиқат танҳо як сохтори сурх хоҳад буд. Барои ин, мо амалҳои GitHub дорем, ки дар он мо метавонем оғози сохтани худро танзим кунем. Пеш аз гузаронидани санҷишҳо, шумо бояд як пойгоҳи додаҳоро бо танзимоти зарурӣ илова кунед. Тавре маълум мешавад, дар Интернет мисолҳои зиёд вуҷуд надоранд, бинобар ин ман ба шумо маслиҳат медиҳам, ки онро дар ҷое захира кунед. Биёед файли .github/workflows/maven.yml-ро навсозӣ кунем:
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Java CI with Maven
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up MySQL
uses: mirromutth/mysql-action@v1.1
with:
mysql version: '5.7'
mysql database: 'dev_jrtb_db'
mysql root password: 'root'
mysql user: 'dev_jrtb_db_user'
mysql password: 'dev_jrtb_db_password'
- name: Set up JDK 1.11
uses: actions/setup-java@v1
with:
java-version: 1.11
- name: Build with Maven
run: mvn -B package --file pom.xml
Ҳоло як блоки нави Set up MySQL мавҷуд аст . Дар он мо MySQL-ро ба раванди CI-и худ илова мекунем ва ҳамзамон тағирёбандаҳои ба мо лозимиро муайян мекунем. Акнун мо ҳама чизеро, ки мехостем, илова кардем. Марҳилаи охирин ин аст, ки тағиротро тела диҳед ва бубинед, ки сохтмон мегузарад ва сабз мешавад.
Навсозии ҳуҷҷатҳо
Биёед versionи лоиҳаро аз 0.3.0-SNAPSHOT то 0.4.0-SNAPSHOT дар pom.xml навсозӣ кунем ва инчунин ба RELEASE_NOTES илова кунем:## 0.4.0-SNAPSHOT
* JRTB-1: added repository layer.
Пас аз ҳамаи ин, мо дархост, тела ва кашидан дархост эҷод мекунем. Ва муҳимтар аз ҳама, сохтмони мо сабз аст!
Истинодҳои муфид:
- Анбори боти телеграммаи мо
- Дархостро бо ҳама тағиротҳои дар мақола тавсифшуда кашед
- Мақолаи SpringBoot + Flyway
- Тасвири MySQL аз DockerHub
- Миёна: Чӣ тавр як мисоли MySql-ро бо Docker Compose эҷод кардан мумкин аст
- Habr: Маълумоти баҳорӣ Jpa
- Канали телеграмм
GO TO FULL VERSION