mirror of
https://github.com/rizinorg/rz-pm.git
synced 2026-11-07 06:45:59 -10:00
Create a custom fake simple plugin for testing (#60)
Using a real plugin means: 1. we need to be online during testing 2. if the plugin has a different version from rizin on the machine often it won't event compile This commit introduces a fake plugin in the simpleplugin directory. During testing, an HTTP server is spawned. The .tar.gz is created and served on-the-fly to every test that asks for it.
This commit is contained in:
1 parent
49f0d96de7
commit
5aafd7a4f3
7 files changed
+274
-30
No files matched your search
+7
-1
@@ -210,7 +210,7 @@ func (rp RizinPackage) downloadGit(artifactsPath string) error {
|
||||
|
||||
// Download the source code of a package and extract it in the provided path
|
||||
func (rp RizinPackage) Download(baseArtifactsPath string) error {
|
||||
log.Printf("Downloading package %s...\n", rp.PackageName)
|
||||
log.Printf("Downloading package %s... from '%s'", rp.PackageName, rp.PackageSource.URL)
|
||||
artifactsPath := rp.artifactsPath(baseArtifactsPath)
|
||||
err := os.MkdirAll(artifactsPath, os.FileMode(0755))
|
||||
if err != nil {
|
||||
@@ -249,6 +249,12 @@ func (rp RizinPackage) buildMeson(site Site) error {
|
||||
cmd.Dir = srcPath
|
||||
cmd.Stdout = log.Writer()
|
||||
cmd.Stderr = log.Writer()
|
||||
|
||||
log.Printf("Running meson setup:")
|
||||
log.Printf("\tdir: %s", srcPath)
|
||||
log.Printf("\targs: %s", strings.Join(args, " "))
|
||||
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+169
-28
@@ -1,10 +1,19 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -25,7 +34,7 @@ func TestDownloadSimplePackage(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
tmpPath, err := os.MkdirTemp(os.TempDir(), "rzpmtest")
|
||||
tmpPath, err := os.MkdirTemp(os.TempDir(), "rzpmtest-artifacts")
|
||||
require.NoError(t, err, "temp path should be created")
|
||||
defer os.RemoveAll(tmpPath)
|
||||
|
||||
@@ -43,7 +52,7 @@ func TestWrongHash(t *testing.T) {
|
||||
PackageDescription: "simple description",
|
||||
PackageVersion: "0.0.1",
|
||||
PackageSource: &RizinPackageSource{
|
||||
URL: "https://github.com/rizinorg/jsdec/archive/refs/tags/v0.7.0.tar.gz",
|
||||
URL: "https://github.com/rizinorg/jsdec/archive/refs/tags/v0.8.0.tar.gz",
|
||||
Hash: "sha256:2b2587dd117d48b284695416a7349a21c4dd30fbe75cc5890ed74945c9b474aa",
|
||||
BuildSystem: "meson",
|
||||
Directory: "p",
|
||||
@@ -113,60 +122,192 @@ func (s FakeSite) Remove() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestInstallSimplePackage(t *testing.T) {
|
||||
log.SetOutput(os.Stderr)
|
||||
p := RizinPackage{
|
||||
// tarGzDir creates a .tar.gz archive at destFile containing the contents of srcDir.
|
||||
func tarGzDir(destFile, srcDir string) error {
|
||||
f, err := os.Create(destFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
gw := gzip.NewWriter(f)
|
||||
defer gw.Close()
|
||||
tw := tar.NewWriter(gw)
|
||||
defer tw.Close()
|
||||
|
||||
return filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
relPath, err := filepath.Rel(srcDir, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if relPath == "." {
|
||||
return nil
|
||||
}
|
||||
header, err := tar.FileInfoHeader(info, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
header.Name = relPath
|
||||
if err := tw.WriteHeader(header); err != nil {
|
||||
return err
|
||||
}
|
||||
if info.Mode().IsRegular() {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = io.Copy(tw, f)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func calcFileSha256(t *testing.T, name string) string {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open file: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
content, err := io.ReadAll(f)
|
||||
require.NoError(t, err, "file should be read")
|
||||
|
||||
h := sha256.Sum256(content)
|
||||
return fmt.Sprintf("%x", h)
|
||||
}
|
||||
|
||||
func serveDirAsTarGz(t *testing.T, ctx context.Context, dir string) (url string, hash string, err error) {
|
||||
tmpFile, err := os.CreateTemp("", "rzpmtest-*.tar.gz")
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to create temp file: %w", err)
|
||||
}
|
||||
|
||||
err = tarGzDir(tmpFile.Name(), dir)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to create tar.gz: %w", err)
|
||||
}
|
||||
|
||||
hash = calcFileSha256(t, tmpFile.Name())
|
||||
|
||||
// Open an HTTP server and serve the file at a random URL
|
||||
mux := http.NewServeMux()
|
||||
fileName := filepath.Base(tmpFile.Name())
|
||||
mux.HandleFunc("/"+fileName, func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, tmpFile.Name())
|
||||
})
|
||||
|
||||
server := &http.Server{
|
||||
Addr: "127.0.0.1:0",
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", server.Addr)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to listen: %w", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
server.Shutdown(context.Background())
|
||||
tmpFile.Close()
|
||||
}()
|
||||
|
||||
go server.Serve(ln)
|
||||
url = fmt.Sprintf("http://%s/%s", ln.Addr().String(), fileName)
|
||||
return url, hash, nil
|
||||
}
|
||||
|
||||
func createTestPackage(t *testing.T, ctx context.Context) RizinPackage {
|
||||
pwd, err := os.Getwd()
|
||||
require.NoError(t, err, "current working directory should be retrieved")
|
||||
|
||||
dir := filepath.Join(filepath.Dir(pwd), "simpleplugin")
|
||||
require.DirExists(t, dir, "test package directory should exist")
|
||||
|
||||
serveURL, hash, err := serveDirAsTarGz(t, ctx, dir)
|
||||
require.NoError(t, err, "failed to serve test package directory as tar.gz")
|
||||
|
||||
simplePackage := RizinPackage{
|
||||
PackageName: "simple",
|
||||
PackageDescription: "simple description",
|
||||
PackageVersion: "0.0.1",
|
||||
PackageSource: &RizinPackageSource{
|
||||
URL: "https://github.com/rizinorg/jsdec/archive/refs/tags/v0.7.0.tar.gz",
|
||||
Hash: "2b2587dd117d48b284695416a7349a21c4dd30fbe75cc5890ed74945c9b474ea",
|
||||
URL: serveURL,
|
||||
Hash: hash,
|
||||
BuildSystem: "meson",
|
||||
Directory: "jsdec-0.7.0",
|
||||
Directory: "",
|
||||
BuildArguments: []string{"-Drizin_plugdir="},
|
||||
},
|
||||
}
|
||||
|
||||
tmpPath, err := os.MkdirTemp(os.TempDir(), "rzpmtest")
|
||||
return simplePackage
|
||||
}
|
||||
|
||||
func TestInstallSimplePackage(t *testing.T) {
|
||||
log.SetOutput(os.Stderr)
|
||||
p := createTestPackage(t, context.Background())
|
||||
|
||||
tmpPath, err := os.MkdirTemp(os.TempDir(), "rzpmtest-build")
|
||||
require.NoError(t, err, "temp path should be created")
|
||||
fmt.Printf("Temporary path for build: %s\n", tmpPath)
|
||||
defer os.RemoveAll(tmpPath)
|
||||
|
||||
pluginsPath, err := os.MkdirTemp(os.TempDir(), "rzpmtest-install")
|
||||
require.NoError(t, err, "install path should be created")
|
||||
fmt.Printf("Temporary path for plugins: %s\n", pluginsPath)
|
||||
defer os.RemoveAll(pluginsPath)
|
||||
p.PackageSource.BuildArguments[0] += pluginsPath
|
||||
|
||||
err = p.Download(tmpPath)
|
||||
require.NoError(t, err, "package should be downloaded")
|
||||
|
||||
installed_files, err := p.Install(FakeSite{ArtifactsDir: tmpPath})
|
||||
assert.NoError(t, err, "The plugin should be built and installed without errors")
|
||||
files, err := ioutil.ReadDir(pluginsPath)
|
||||
installedFiles, err := p.Install(FakeSite{ArtifactsDir: tmpPath})
|
||||
require.NoError(t, err, "The plugin should be built and installed without errors")
|
||||
|
||||
files, err := os.ReadDir(pluginsPath)
|
||||
fmt.Printf("Installed files: %v\n", installedFiles)
|
||||
fmt.Printf("Found files in pluginsPath: %v\n", files)
|
||||
|
||||
require.NoError(t, err, "pluginsPath should be read")
|
||||
require.True(t, len(files) >= 1, "there should be one plugin installed")
|
||||
for i := range files {
|
||||
assert.Contains(t, files[i].Name(), "core_pdd", "the name of the plugin lib is jsdec")
|
||||
|
||||
// check that every file in pluginsPath is in installedFiles
|
||||
installedFileMap := make(map[string]bool)
|
||||
for _, file := range installedFiles {
|
||||
name := filepath.Base(file)
|
||||
installedFileMap[name] = true
|
||||
}
|
||||
for i := range installed_files {
|
||||
assert.Contains(t, installed_files[i], "core_pdd", "jsdec should install core_pdd in plugins dir")
|
||||
|
||||
for _, file := range files {
|
||||
assert.Contains(t, installedFileMap, file.Name(), "installed files should match the files in pluginsPath")
|
||||
}
|
||||
|
||||
file := files[0]
|
||||
if runtime.GOOS == "windows" {
|
||||
assert.Contains(t, file.Name(), "plugin.dll", "the name of the plugin should contain 'plugin.dll'")
|
||||
} else if runtime.GOOS == "darwin" {
|
||||
assert.Contains(t, file.Name(), "libplugin.dylib", "the name of the plugin should contain 'plugin.dylib'")
|
||||
} else {
|
||||
assert.Contains(t, file.Name(), "libplugin.so", "the name of the plugin should contain 'plugin.so'")
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
assert.Contains(t, file.Name(), "plugin", "the name of the plugin should contain 'plugin'")
|
||||
}
|
||||
|
||||
for _, file := range installedFiles {
|
||||
assert.Contains(t, file, "plugin", "the name of the plugin should contain 'plugin'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUninstallSimplePackage(t *testing.T) {
|
||||
log.SetOutput(os.Stderr)
|
||||
p := RizinPackage{
|
||||
PackageName: "simple",
|
||||
PackageDescription: "simple description",
|
||||
PackageVersion: "0.0.1",
|
||||
PackageSource: &RizinPackageSource{
|
||||
URL: "https://github.com/rizinorg/jsdec/archive/refs/tags/v0.7.0.tar.gz",
|
||||
Hash: "2b2587dd117d48b284695416a7349a21c4dd30fbe75cc5890ed74945c9b474ea",
|
||||
BuildSystem: "meson",
|
||||
Directory: "jsdec-0.7.0",
|
||||
BuildArguments: []string{"-Drizin_plugdir="},
|
||||
},
|
||||
}
|
||||
p := createTestPackage(t, context.Background())
|
||||
|
||||
tmpPath, err := os.MkdirTemp(os.TempDir(), "rzpmtest")
|
||||
require.NoError(t, err, "temp path should be created")
|
||||
|
||||
+11
-1
@@ -4,5 +4,15 @@ import "strings"
|
||||
|
||||
func GetMajorMinorVersion(version string) string {
|
||||
splits := strings.SplitN(version, ".", 3)
|
||||
return splits[0] + "." + splits[1]
|
||||
var major, minor string
|
||||
|
||||
major = splits[0]
|
||||
if len(splits) < 2 {
|
||||
// If there is no minor version, return the major version with a ".0"
|
||||
minor = "0"
|
||||
} else {
|
||||
minor = splits[1]
|
||||
}
|
||||
|
||||
return major + "." + minor
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package pkg
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGetMajorMinorVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
version string
|
||||
want string
|
||||
}{
|
||||
{"1.2.3", "1.2"},
|
||||
{"10.20.30", "10.20"},
|
||||
{"0.1.2", "0.1"},
|
||||
{"5.6", "5.6"}, // Edge case with no patch version
|
||||
{"1", "1.0"}, // Edge case with only major version
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.version, func(t *testing.T) {
|
||||
got := GetMajorMinorVersion(tt.version)
|
||||
if got != tt.want {
|
||||
t.Errorf("GetMajorMinorVersion(%q) = %q; want %q", tt.version, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
project('simple_project', 'c')
|
||||
|
||||
rz_core_dep = dependency('rz_core')
|
||||
plugins_dir = get_option('rizin_plugdir')
|
||||
message('Plugins install directory: ' + plugins_dir)
|
||||
|
||||
library(
|
||||
'plugin',
|
||||
['plugin.c'],
|
||||
dependencies: [rz_core_dep],
|
||||
install: true,
|
||||
install_dir: plugins_dir,
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
option(
|
||||
'rizin_plugdir',
|
||||
type: 'string',
|
||||
description: 'Rizin plugin directory',
|
||||
)
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
|
||||
// SPDX-FileCopyrightText: 2025 Eyad Issa <[email protected]>
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include <rz_analysis.h>
|
||||
#include <rz_cmd.h>
|
||||
#include <rz_cons.h>
|
||||
#include <rz_core.h>
|
||||
#include <rz_lib.h>
|
||||
#include <rz_types.h>
|
||||
|
||||
static bool rz_cmd_init(RzCore *core) {
|
||||
// no-op plugin, does nothing
|
||||
RZ_LOG_INFO("Initializing simple plugin\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rz_cmd_fini(RzCore *core) {
|
||||
// no-op plugin, does nothing
|
||||
RZ_LOG_INFO("Finalizing simple plugin\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
RzCorePlugin rz_core_plugin_example = {
|
||||
.name = "simple-plugin",
|
||||
.desc = "A simple no-op plugin for Rizin",
|
||||
.license = "BSD-3-Clause",
|
||||
.init = rz_cmd_init,
|
||||
.fini = rz_cmd_fini,
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _RZ_API __declspec(dllexport)
|
||||
#else
|
||||
#define _RZ_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#ifndef CORELIB
|
||||
_RZ_API RzLibStruct rizin_plugin = {
|
||||
.type = RZ_LIB_TYPE_CORE,
|
||||
.data = &rz_core_plugin_example,
|
||||
.version = RZ_VERSION,
|
||||
};
|
||||
#endif
|
||||
Reference in new issue
Block a user