* add release access and branch access(#515)

* add release and branch access(#515)

* always update to latest release(#515)

* #515

* #515

* add testcases(#515)

* fix 515

* fix 515

* deal with connection refused

* disable disk operation related test

* fix #592

* fix #515 & #592

* mockito test

* ignored network related test

* resolve conflict
pull/943/head
BigBang019 2020-07-02 23:34:47 +08:00 committed by GitHub
parent cd9aa23706
commit 2b99bd599f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 867 additions and 36 deletions

View File

@ -69,9 +69,13 @@ ext {
jedisVersion= '3.3.0'
zxingVersion = "3.4.0"
huaweiObsVersion = "3.19.7"
githubApiVersion = "1.84"
powermockVersion = "1.6.6"
mockitoVersion = "1.10.19"
}
dependencies {
implementation "org.kohsuke:github-api:$githubApiVersion"
implementation "org.springframework.boot:spring-boot-starter-actuator"
implementation "org.springframework.boot:spring-boot-starter-data-jpa"
implementation "org.springframework.boot:spring-boot-starter-web"
@ -131,5 +135,13 @@ dependencies {
testImplementation "org.springframework.boot:spring-boot-starter-test"
testCompile group: 'org.mockito', name: 'mockito-all', version: "$mockitoVersion"
testCompile group: 'org.powermock', name: 'powermock-api-mockito', version: "$powermockVersion"
testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: "$powermockVersion"
developmentOnly "org.springframework.boot:spring-boot-devtools"
}
test {
useJUnitPlatform()
}

View File

@ -175,10 +175,39 @@ public class ThemeController {
return themeService.fetch(uri);
}
@PostMapping("fetchingBranches")
@ApiOperation("Fetches all branches")
public List<ThemeProperty> fetchBranches(@RequestParam("uri") String uri) {
return themeService.fetchBranches(uri);
}
@PostMapping("fetchingReleases")
@ApiOperation("Fetches all releases")
public List<ThemeProperty> fetchReleases(@RequestParam("uri") String uri) {
return themeService.fetchReleases(uri);
}
@GetMapping("fetchingRelease")
@ApiOperation("Fetches a specific release")
public ThemeProperty fetchRelease(@RequestParam("uri") String uri, @RequestParam("tag") String tagName) {
return themeService.fetchRelease(uri, tagName);
}
@GetMapping("fetchBranch")
@ApiOperation("Fetch specific branch")
public ThemeProperty fetchBranch(@RequestParam("uri") String uri, @RequestParam("branch") String branchName) {
return themeService.fetchBranch(uri, branchName);
}
@GetMapping("fetchLatestRelease")
@ApiOperation("Fetch latest release")
public ThemeProperty fetchLatestRelease(@RequestParam("uri") String uri) {
return themeService.fetchLatestRelease(uri);
}
@PutMapping("fetching/{themeId}")
@ApiOperation("Upgrades theme by remote")
public ThemeProperty updateThemeByFetching(@PathVariable("themeId") String themeId) {
return themeService.update(themeId);
}

View File

@ -88,13 +88,23 @@ public interface ThemeService {
/**
* Theme provider remote name.
*/
String THEME_PROVIDER_REMOTE_NAME = "theme-provider";
String THEME_PROVIDER_REMOTE_NAME = "origin";
/**
* Default remote branch name.
*/
String DEFAULT_REMOTE_BRANCH = "master";
/**
* Key to access the zip file url which is in the http response
*/
String ZIP_FILE_KEY = "zipball_url";
/**
* Key to access the tag name which is in the http response
*/
String TAG_KEY = "tag_name";
/**
* Get theme property by theme id.
*
@ -303,6 +313,53 @@ public interface ThemeService {
@NonNull
ThemeProperty fetch(@NonNull String uri);
/**
* Fetches the latest release
*
* @param uri theme remote uri must not be null
* @return theme property
*/
@NonNull
ThemeProperty fetchLatestRelease(@NonNull String uri);
/**
* Fetches all the branches info
*
* @param uri theme remote uri must not be null
* @return list of theme properties
*/
@NonNull
List<ThemeProperty> fetchBranches(@NonNull String uri);
/**
* Fetches all the release info
*
* @param uri theme remote uri must not be null
* @return list of theme properties
*/
@NonNull
List<ThemeProperty> fetchReleases(@NonNull String uri);
/**
* Fetches a specific release
*
* @param uri theme remote uri must not be null
* @param tagName release tag name must not be null
* @return theme property
*/
@NonNull
ThemeProperty fetchRelease(@NonNull String uri, @NonNull String tagName);
/**
* Fetches a specific branch (clone)
*
* @param uri theme remote uri must not be null
* @param branchName wanted branch must not be null
* @return theme property
*/
@NonNull
ThemeProperty fetchBranch(@NonNull String uri, @NonNull String branchName);
/**
* Reloads themes
*/

View File

@ -493,9 +493,9 @@ public class ThemeServiceImpl implements ThemeService {
if (StringUtils.endsWithIgnoreCase(uri, ".zip")) {
downloadZipAndUnzip(uri, themeTmpPath);
} else {
uri = StringUtils.appendIfMissingIgnoreCase(uri, ".git", ".git");
String repoUrl = StringUtils.appendIfMissingIgnoreCase(uri, ".git", ".git");
// Clone from git
GitUtils.cloneFromGit(uri, themeTmpPath);
GitUtils.cloneFromGit(repoUrl, themeTmpPath);
}
return add(themeTmpPath);
@ -506,6 +506,125 @@ public class ThemeServiceImpl implements ThemeService {
}
}
@Override
public ThemeProperty fetchBranch(String uri, String branchName) {
Assert.hasText(uri, "Theme remote uri must not be blank");
Path tmpPath = null;
try {
// Create temp path
tmpPath = FileUtils.createTempDirectory();
// Create temp path
Path themeTmpPath = tmpPath.resolve(HaloUtils.randomUUIDWithoutDash());
String repoUrl = StringUtils.appendIfMissingIgnoreCase(uri, ".git", ".git");
GitUtils.cloneFromGit(repoUrl, themeTmpPath, branchName);
return add(themeTmpPath);
} catch (IOException | GitAPIException e) {
throw new ServiceException("主题拉取失败 " + uri, e);
} finally {
FileUtils.deleteFolderQuietly(tmpPath);
}
}
@Override
public ThemeProperty fetchRelease(@NonNull String uri, @NonNull String tagName) {
Assert.hasText(uri, "Theme remote uri must not be blank");
Assert.hasText(tagName, "Theme remote tagName must not be blank");
Path tmpPath = null;
try {
tmpPath = FileUtils.createTempDirectory();
Path themeTmpPath = tmpPath.resolve(HaloUtils.randomUUIDWithoutDash());
Map<String, Object> releaseInfo = GithubUtils.getRelease(uri, tagName);
if (releaseInfo == null) {
throw new ServiceException("主题拉取失败" + uri);
}
String zipUrl = (String) releaseInfo.get(ZIP_FILE_KEY);
downloadZipAndUnzip(zipUrl, themeTmpPath);
return add(themeTmpPath);
} catch (IOException e) {
throw new ServiceException("主题拉取失败 " + uri, e);
} finally {
FileUtils.deleteFolderQuietly(tmpPath);
}
}
@Override
public ThemeProperty fetchLatestRelease(@NonNull String uri) {
Assert.hasText(uri, "Theme remote uri must not be blank");
Path tmpPath = null;
try {
tmpPath = FileUtils.createTempDirectory();
Path themeTmpPath = tmpPath.resolve(HaloUtils.randomUUIDWithoutDash());
Map<String, Object> releaseInfo = GithubUtils.getLatestRelease(uri);
if (releaseInfo == null) {
throw new ServiceException("主题拉取失败" + uri);
}
String zipUrl = (String) releaseInfo.get(ZIP_FILE_KEY);
downloadZipAndUnzip(zipUrl, themeTmpPath);
return add(themeTmpPath);
} catch (IOException e) {
throw new ServiceException("主题拉取失败 " + uri, e);
} finally {
FileUtils.deleteFolderQuietly(tmpPath);
}
}
@Override
public List<ThemeProperty> fetchBranches(String uri) {
Assert.hasText(uri, "Theme remote uri must not be blank");
String repoUrl = StringUtils.appendIfMissingIgnoreCase(uri, ".git",".git");
List<String> branches = GitUtils.getAllBranches(repoUrl);
List<ThemeProperty> themeProperties = new ArrayList<>();
branches.forEach(branch -> {
ThemeProperty themeProperty = new ThemeProperty();
themeProperty.setBranch(branch);
themeProperties.add(themeProperty);
});
return themeProperties;
}
@Override
public List<ThemeProperty> fetchReleases(@NonNull String uri) {
Assert.hasText(uri, "Theme remote uri must not be blank");
List<String> releases = GithubUtils.getReleases(uri);
List<ThemeProperty> themeProperties = new ArrayList<>();
if (releases == null) {
throw new ServiceException("主题拉取失败");
}
releases.forEach(tagName -> {
ThemeProperty themeProperty = new ThemeProperty();
themeProperty.setBranch(tagName);
themeProperties.add(themeProperty);
});
return themeProperties;
}
@Override
public void reload() {
eventPublisher.publishEvent(new ThemeUpdatedEvent(this));
@ -519,6 +638,7 @@ public class ThemeServiceImpl implements ThemeService {
try {
pullFromGit(updatingTheme);
} catch (Exception e) {
if (e instanceof ThemeNotSupportException) {
throw (ThemeNotSupportException) e;
@ -597,7 +717,7 @@ public class ThemeServiceImpl implements ThemeService {
// Get branch
String branch = StringUtils.isBlank(themeProperty.getBranch()) ?
DEFAULT_REMOTE_BRANCH : themeProperty.getBranch();
DEFAULT_REMOTE_BRANCH : themeProperty.getBranch();
Git git = null;
@ -606,6 +726,13 @@ public class ThemeServiceImpl implements ThemeService {
Repository repository = git.getRepository();
// Add all changes
git.add()
.addFilepattern(".")
.call();
// Commit the changes
git.commit().setMessage("Commit by halo automatically").call();
RevWalk revWalk = new RevWalk(repository);
Ref ref = repository.findRef(Constants.HEAD);
@ -617,38 +744,31 @@ public class ThemeServiceImpl implements ThemeService {
// Force to set remote name
git.remoteRemove().setRemoteName(THEME_PROVIDER_REMOTE_NAME).call();
RemoteConfig remoteConfig = git.remoteAdd()
.setName(THEME_PROVIDER_REMOTE_NAME)
.setUri(new URIish(themeProperty.getRepo()))
.call();
// Add all changes
git.add()
.addFilepattern(".")
.call();
// Commit the changes
git.commit().setMessage("Commit by halo automatically").call();
.setName(THEME_PROVIDER_REMOTE_NAME)
.setUri(new URIish(themeProperty.getRepo()))
.call();
// Check out to specified branch
if (!StringUtils.equalsIgnoreCase(branch, git.getRepository().getBranch())) {
boolean present = git.branchList()
.call()
.stream()
.map(Ref::getName)
.anyMatch(name -> StringUtils.equalsIgnoreCase(name, branch));
.call()
.stream()
.map(Ref::getName)
.anyMatch(name -> StringUtils.equalsIgnoreCase(name, branch));
git.checkout()
.setCreateBranch(true)
.setForced(!present)
.setName(branch)
.call();
.setCreateBranch(true)
.setForced(!present)
.setName(branch)
.call();
}
// Pull with rebasing
PullResult pullResult = git.pull()
.setRemote(remoteConfig.getName())
.setRemoteBranchName(branch)
.setRebase(true)
.call();
.setRemote(remoteConfig.getName())
.setRemoteBranchName(branch)
.setRebase(true)
.call();
if (!pullResult.isSuccessful()) {
log.debug("Rebase result: [{}]", pullResult.getRebaseResult());
@ -657,6 +777,9 @@ public class ThemeServiceImpl implements ThemeService {
throw new ThemeUpdateException("拉取失败!您与主题作者可能同时更改了同一个文件");
}
String latestTagName = (String) GithubUtils.getLatestRelease(themeProperty.getRepo()).get(TAG_KEY);
git.checkout().setName(latestTagName).call();
// updated successfully.
ThemeProperty updatedThemeProperty = getProperty(Paths.get(themeProperty.getThemePath()));
@ -664,9 +787,9 @@ public class ThemeServiceImpl implements ThemeService {
if (StringUtils.isNotEmpty(updatedThemeProperty.getRequire()) && !VersionUtil.compareVersion(HaloConst.HALO_VERSION, updatedThemeProperty.getRequire())) {
// reset theme version
git.reset()
.setMode(ResetCommand.ResetType.HARD)
.setRef(lastCommit.getName())
.call();
.setMode(ResetCommand.ResetType.HARD)
.setRef(lastCommit.getName())
.call();
throw new ThemeNotSupportException("新版本主题仅支持 Halo " + updatedThemeProperty.getRequire() + " 以上的版本");
}
} finally {
@ -696,7 +819,6 @@ public class ThemeServiceImpl implements ThemeService {
}
log.debug("Downloaded [{}]", zipUrl);
// Unzip it
FileUtils.unzip(downloadResponse.getBody(), targetPath);
}

View File

@ -10,6 +10,7 @@ import run.halo.app.exception.ForbiddenException;
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -131,6 +132,19 @@ public class FileUtils {
zipEntry = zis.getNextEntry();
}
File targetDir = targetPath.toFile();
List<File> files = Arrays.asList(targetDir.listFiles());
// if zip file has root file
if (files.size() == 1 && files.get(0).isDirectory()) {
String rootPath = files.get(0).toPath().toString();
String rootFile = rootPath.substring(rootPath.lastIndexOf("/", rootPath.length() - 1) + 1,rootPath.length());
List<File> propertyFiles = Arrays.asList(files.get(0).listFiles());
for (File propertyFile : propertyFiles) {
String filePath = propertyFile.toPath().toString();
String destPath = filePath.replace(rootFile, "");
Files.copy(propertyFile.toPath(), Paths.get(destPath));
}
}
}
/**

View File

@ -3,13 +3,17 @@ package run.halo.app.utils;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.storage.file.WindowCacheConfig;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import java.io.IOException;
import java.nio.file.Path;
import java.util.*;
/**
* Git utilities.
@ -59,6 +63,43 @@ public class GitUtils {
return git;
}
public static void cloneFromGit(@NonNull String repoUrl, @NonNull Path targetPath, @NonNull String branchName) throws GitAPIException {
Assert.hasText(repoUrl, "Repository remote url must not be blank");
Assert.notNull(targetPath, "Target path must not be null");
Git git = null;
try {
git = Git.cloneRepository()
.setURI(repoUrl)
.setDirectory(targetPath.toFile())
.setBranchesToClone(Arrays.asList("refs/heads/" + branchName))
.setBranch("refs/heads/" + branchName)
.call();
} finally {
closeQuietly(git);
}
}
public static List<String> getAllBranches(@NonNull String repoUrl) {
List<String> branches = new ArrayList<String>();
try {
Collection<Ref> refs = Git.lsRemoteRepository()
.setHeads(true)
.setRemote(repoUrl)
.call();
for (Ref ref : refs) {
branches.add(ref.getName().substring(ref.getName().lastIndexOf("/") + 1, ref.getName().length()));
}
} catch (InvalidRemoteException e) {
log.warn("Git url is not valid", e);
} catch (TransportException e) {
log.warn("Transport exception", e);
} catch (GitAPIException e) {
log.warn("Git api exception", e);
}
return branches;
}
public static void closeQuietly(Git git) {
if (git != null) {
git.getRepository().close();

View File

@ -0,0 +1,368 @@
package run.halo.app.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.kohsuke.github.*;
import run.halo.app.service.ThemeService;
import java.io.FileNotFoundException;
import java.util.*;
/**
* GithubUtils send request to api.github.com
*
* @author bigbang019
* @date 2020-05-31
*/
@Slf4j
public class GithubUtils {
/**
* The prefix need to remove
*/
static final String PREFIX = "https://github.com/";
/**
* Get latest release
* @param uri repository url must not be null
* @return the map object containning tagname and zipfile url
*/
public static Map<String, Object> getLatestRelease(String uri) {
String repoUrl = StringUtils.removeStartIgnoreCase(uri, PREFIX);
try {
GithubLatestRelease githubLatestRelease = new GithubLatestRelease(repoUrl);
Thread thread = new Thread(githubLatestRelease);
thread.start();
thread.join(10 * 1000);
return githubLatestRelease.result;
} catch (InterruptedException e) {
log.warn("Interrupted", e);
}
return null;
}
/**
* Get release information
* @param uri repository url must not be null
* @return list of tagname of releases
*/
public static List<String> getReleases(String uri) {
String repoUrl = StringUtils.removeStartIgnoreCase(uri, PREFIX);
try {
GithubReleases githubReleases = new GithubReleases(repoUrl);
Thread thread = new Thread(githubReleases);
thread.start();
thread.join(10 * 1000);
return githubReleases.result;
} catch (InterruptedException e) {
log.warn("Interrupted", e);
}
return null;
}
/**
* Get release information
* @param uri repository url must not be null
* @param tagName tag must not be null
* @return the map object containning tagname and zipfile url
*/
public static Map<String, Object> getRelease(String uri, String tagName) {
String repoUrl = StringUtils.removeStartIgnoreCase(uri, PREFIX);
try {
GithubRelease githubRelease = new GithubRelease(repoUrl, tagName);
Thread thread = new Thread(githubRelease);
thread.start();
thread.join(10 * 1000);
return githubRelease.result;
} catch (InterruptedException e) {
log.warn("Interrupted", e);
}
return null;
}
/**
* Get the content of theme.yaml/theme.yml
* @param uri repository url must not be null
* @param branch branch must not be null
* @return content of the file
*/
public static String accessThemeProperty(String uri, String branch) {
String repoUrl = StringUtils.removeStartIgnoreCase(uri, PREFIX);
try {
GithubFile githubFile = new GithubFile(repoUrl, branch);
Thread thread = new Thread(githubFile);
thread.start();
thread.join(10 * 1000);
return githubFile.result;
} catch (InterruptedException e) {
log.warn("Interrupted", e);
}
return null;
}
private static class GithubRelease implements Runnable {
/**
* The return result is zip url and tag name etc.
*/
private HashMap<String, Object> result;
/**
* should be in format of "username/reponame"
*/
private String repoUrl;
private String tagName;
public GithubRelease(String repoUrl, String tagName) {
this.repoUrl = repoUrl;
this.tagName = tagName;
result = null;
}
@Override
public void run() {
while (true) {
try {
GitHub gitHub = GitHub.connectAnonymously();
GHRepository ghRepository = gitHub.getRepository(repoUrl);
List<GHRelease> ghReleaseList = ghRepository.getReleases();
if (ghReleaseList.size() == 0) {
break;
}
Optional<GHRelease> res = ghReleaseList.stream()
.filter(release -> StringUtils.equalsIgnoreCase(release.getTagName(), tagName))
.findFirst();
if (res.isPresent()) {
GHRelease ghRelease = res.get();
result = new HashMap<String, Object>() {
{
put(ThemeService.ZIP_FILE_KEY, ghRelease.getZipballUrl());
put(ThemeService.TAG_KEY, ghRelease.getTagName());
}
};
}
break;
} catch (Exception e) {
if (e instanceof HttpException) {
int code = ((HttpException) e).getResponseCode();
if (code != -1) {
break;
}
} else {
break;
}
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
break;
}
}
}
}
private static class GithubReleases implements Runnable {
private List<String> result;
private String repoUrl;
public GithubReleases(String repoUrl) {
this.repoUrl = repoUrl;
result = null;
}
@Override
public void run() {
while (true) {
try {
GitHub gitHub = GitHub.connectAnonymously();
GHRepository ghRepository = gitHub.getRepository(repoUrl);
List<GHRelease> ghReleaseList = ghRepository.getReleases();
result = new ArrayList<String>();
for (GHRelease ghRelease : ghReleaseList) {
result.add(ghRelease.getTagName());
}
break;
} catch (Exception e) {
if (e instanceof HttpException) {
int code = ((HttpException) e).getResponseCode();
if (code != -1) {
break;
}
} else {
break;
}
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
break;
}
}
}
}
private static class GithubLatestRelease implements Runnable {
/**
* The return result is zip url and tag name etc.
*/
private HashMap<String, Object> result;
/**
* should be in format of "username/reponame"
*/
private String repoUrl;
public GithubLatestRelease(String repoUrl) {
this.repoUrl = repoUrl;
result = null;
}
@Override
public void run() {
while (true) {
try {
GitHub gitHub = GitHub.connectAnonymously();
GHRepository ghRepository = gitHub.getRepository(repoUrl);
List<GHRelease> ghReleaseList = ghRepository.getReleases();
if (ghReleaseList.size() == 0) {
break;
}
GHRelease ghRelease = ghReleaseList.get(0);
result = new HashMap<String, Object>() {
{
put(ThemeService.ZIP_FILE_KEY, ghRelease.getZipballUrl());
put(ThemeService.TAG_KEY, ghRelease.getTagName());
}
};
break;
} catch (Exception e) {
if (e instanceof HttpException) {
int code = ((HttpException) e).getResponseCode();
if (code != -1) {
break;
}
} else {
break;
}
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
break;
}
}
}
}
private static class GithubFile implements Runnable {
/**
* result is file content
*/
private String result;
/**
* should be in format of "username/reponame"
*/
private String repoUrl;
/**
* the branch name
*/
private String branch;
public GithubFile(String repoUrl, String branch) {
this.repoUrl = repoUrl;
this.branch = branch;
result = null;
}
@Override
public void run() {
while (true) {
try {
GitHub gitHub = GitHub.connectAnonymously();
GHRepository ghRepository = gitHub.getRepository(repoUrl);
GHContent ghContent = null;
for (String themePropertyFile : ThemeService.THEME_PROPERTY_FILE_NAMES) {
try {
ghContent = ghRepository.getFileContent(themePropertyFile, branch);
} catch (FileNotFoundException e) {
}
}
if (ghContent == null) {
break;
}
result = ghContent.getContent();
break;
} catch (Exception e) {
if (e instanceof HttpException) {
int code = ((HttpException) e).getResponseCode();
if (code != -1) {
break;
}
} else {
break;
}
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
}
}
}

View File

@ -5,7 +5,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.runners.MockitoJUnitRunner;
import run.halo.app.cache.AbstractStringCacheStore;
import run.halo.app.model.entity.Option;
import run.halo.app.model.properties.QiniuOssProperties;

View File

@ -0,0 +1,130 @@
package run.halo.app.service.impl;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.client.RestTemplate;
import run.halo.app.cache.AbstractStringCacheStore;
import run.halo.app.config.properties.HaloProperties;
import run.halo.app.handler.theme.config.ThemeConfigResolver;
import run.halo.app.handler.theme.config.support.ThemeProperty;
import run.halo.app.service.OptionService;
import run.halo.app.utils.FileUtils;
import run.halo.app.utils.GitUtils;
import run.halo.app.utils.GithubUtils;
import java.io.File;
import java.nio.file.Path;
import java.util.*;
@RunWith(PowerMockRunner.class)
@PrepareForTest({GitUtils.class, GithubUtils.class, FileUtils.class, ThemeServiceImpl.class})
public class ThemeServiceImplTest {
@Mock
private HaloProperties haloProperties;
@Mock
private OptionService optionService;
@Mock
private AbstractStringCacheStore cacheStore;
@Mock
private ThemeConfigResolver themeConfigResolver;
@Mock
private RestTemplate restTemplate;
@Mock
private ApplicationEventPublisher eventPublisher;
@InjectMocks
public ThemeServiceImpl themeService;
@Before
public void setUp() throws Exception {
//Static Method
PowerMockito.mockStatic(GithubUtils.class);
PowerMockito.mockStatic(GitUtils.class);
PowerMockito.mockStatic(FileUtils.class);
PowerMockito.doReturn(Arrays.asList("master", "dev")).when(GitUtils.class, "getAllBranches", Mockito.any(String.class));
PowerMockito.doNothing().when(GitUtils.class, "cloneFromGit", Mockito.any(String.class), Mockito.any(Path.class));
PowerMockito.doReturn("propertyContent").when(GithubUtils.class, "accessThemeProperty", Mockito.any(String.class), Mockito.any(String.class));
PowerMockito.doReturn(new File("tmpPath").toPath()).when(FileUtils.class, "createTempDirectory");
PowerMockito.doNothing().when(FileUtils.class, "deleteFolderQuietly", Mockito.any(Path.class));
//Method
themeService = PowerMockito.spy(new ThemeServiceImpl(haloProperties, optionService, cacheStore, themeConfigResolver, restTemplate, eventPublisher));
Mockito.doNothing().when(eventPublisher).publishEvent(Mockito.any(String.class));
}
@Test
public void fetchGitTest() throws Exception {
String uri = "https://github.com/halo-dev/halo-theme-pinghsu";
PowerMockito.doNothing().when(themeService, "downloadZipAndUnzip", Mockito.any(String.class), Mockito.any(Path.class));
PowerMockito.doReturn(new ThemeProperty()).when(themeService, "add", Mockito.any(Path.class));
ThemeProperty themeProperty = themeService.fetch(uri);
Assert.assertNotNull(themeProperty);
}
@Test
public void fetchZipTest() throws Exception {
String uri = "https://github.com/halo-dev/halo-theme-pinghsu/archive/master.zip";
PowerMockito.doNothing().when(themeService, "downloadZipAndUnzip", Mockito.any(String.class), Mockito.any(Path.class));
PowerMockito.doReturn(new ThemeProperty()).when(themeService, "add", Mockito.any(Path.class));
ThemeProperty themeProperty = themeService.fetch(uri);
Assert.assertNotNull(themeProperty);
}
@Test
public void fetchBranchesTest() {
String uri = "https://github.com/halo-dev/halo-theme-hux";
List<ThemeProperty> themeProperties = themeService.fetchBranches(uri);
Assert.assertNotNull(themeProperties);
Assert.assertEquals(themeProperties.size(), 2);
}
@Test
public void fetchBranchTest() throws Exception {
String uri = "https://github.com/halo-dev/halo-theme-casper";
String branch = "master";
PowerMockito.doNothing().when(themeService, "downloadZipAndUnzip", Mockito.any(String.class), Mockito.any(Path.class));
PowerMockito.doReturn(new ThemeProperty()).when(themeService, "add", Mockito.any(Path.class));
ThemeProperty themeProperty = themeService.fetchBranch(uri, branch);
Assert.assertNotNull(themeProperty);
}
@Test
public void fetchLatestReleaseTest() throws Exception {
String uri = "https://github.com/halo-dev/halo-theme-casper";
PowerMockito.doNothing().when(themeService, "downloadZipAndUnzip", Mockito.any(String.class), Mockito.any(Path.class));
PowerMockito.doReturn(new ThemeProperty()).when(themeService, "add", Mockito.any(Path.class));
ThemeProperty themeProperty = themeService.fetchLatestRelease(uri);
Assert.assertNotNull(themeProperty);
}
@Test
public void updateTest() throws Exception {
PowerMockito.doNothing().when(themeService, "downloadZipAndUnzip", Mockito.any(String.class), Mockito.any(Path.class));
PowerMockito.doReturn(new ThemeProperty()).when(themeService, "add", Mockito.any(Path.class));
PowerMockito.doNothing().when(themeService, "pullFromGit", Mockito.any(ThemeProperty.class));
PowerMockito.doReturn(new ThemeProperty()).when(themeService, "getThemeOfNonNullBy", Mockito.any(String.class));
ThemeProperty themeProperty = themeService.update("String");
Assert.assertNotNull(themeProperty);
}
}

View File

@ -7,10 +7,7 @@ import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.*;
import java.io.IOException;
import java.net.URISyntaxException;
@ -80,6 +77,21 @@ public class GitTest {
git.close();
}
@Test
@Ignore
public void getAllBranchesTest() {
List<String> branches = GitUtils.getAllBranches("https://github.com/halo-dev/halo-theme-hux.git");
Assert.assertNotNull(branches);
}
@Test
@Ignore
public void getAllBranchesWithInvalidURL() {
List<String> branches = GitUtils.getAllBranches("https://github.com/halo-dev/halo-theme.git");
Assert.assertNotNull(branches);
Assert.assertEquals(branches.size(), 0);
}
private Git cloneRepository() throws GitAPIException {
return Git.cloneRepository()
.setURI("https://github.com/halo-dev/halo-theme-pinghsu.git")

View File

@ -0,0 +1,46 @@
package run.halo.app.utils;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import java.util.List;
import java.util.Map;
@Slf4j
public class GithubUtilsTest {
@Test
@Ignore
public void getLatestReleasesWithValidURL() {
Map<String, Object> map = GithubUtils.getLatestRelease("https://github.com/halo-dev/halo-theme-hux");
}
@Test
@Ignore
public void getLatestReleasesWithInvalidURL() {
Map<String, Object> map = GithubUtils.getLatestRelease("https://github.com/halo-dev/halo-theme-hu");
Assert.assertNull(map);
}
@Test
@Ignore
public void accessThemePropertyWithValidURL() {
String content = GithubUtils.accessThemeProperty("https://github.com/halo-dev/halo-theme-hux", "master");
}
@Test
@Ignore
public void accessThemePropertyWithInvalidURL() {
String content = GithubUtils.accessThemeProperty("https://github.com/halo-dev/halo-theme-hu", "master");
Assert.assertNull(content);
}
@Test
@Ignore
public void getReleasesTest() {
List<String> list = GithubUtils.getReleases("https://github.com/halo-dev/halo-theme-hux");
}
}