Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 36 additions & 13 deletions src/services/downloader.test.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,49 @@
import { assertExists } from "https://deno.land/std@0.206.0/assert/assert_exists.ts";
import { Downloader } from "./downloader.ts";
import { removeStackQLDownload } from "../../testing/utils.ts";
import {
assertSpyCalls,
spy,
} from "https://deno.land/std@0.207.0/testing/mock.ts";

Deno.test("Downloader setupStackQL Integration Test", async () => {
Deno.test("Downloader setupStackQL and upgrade Test", async () => {
// Arrange
await removeStackQLDownload();
const downloader = new Downloader();
let binaryPath: string;
const denoOpenSpy = spy(Deno, "open");

// Act
try {
binaryPath = await downloader.setupStackQL();
const setupTest = async () => {
try {
binaryPath = await downloader.setupStackQL();

// Assert
assertExists(binaryPath);
// Check if the binary exists after setupStackQL is called
// Assert
assertExists(binaryPath);
assertSpyCalls(denoOpenSpy, 1);
// Check if the binary exists after setupStackQL is called

console.log(
"Test passed: setupStackQL completed without errors and binary exists.",
);
} catch (error) {
console.error("Test failed:", error);
throw error; // This will cause the test to fail
}
console.log(
"Test passed: setupStackQL completed without errors and binary exists."
);
} catch (error) {
console.error("Test failed:", error);
throw error; // This will cause the test to fail
}
};

const upgradeTest = async () => {
try {
binaryPath = await downloader.upgradeStackQL();

assertExists(binaryPath);
assertSpyCalls(denoOpenSpy, 2);
} catch (error) {
console.error("Test failed:", error);
throw error; // This will cause the test to fail
}
};

await setupTest();
await upgradeTest();
});
84 changes: 60 additions & 24 deletions src/services/downloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export class Downloader {
private os: string;
private arch: string;
private urlMap: Record<string, string>;

constructor() {
this.os = Deno.build.os; // 'linux', 'darwin', or 'windows'
this.arch = Deno.build.arch; // 'x86_64', 'arm64', etc.
Expand All @@ -25,11 +24,13 @@ export class Downloader {

private async downloadFile(url: string, downloadDir: string) {
const res = await fetch(url);
// create dir if not exists

const file = await Deno.open(downloadDir, { create: true, write: true });

try {
await res.body?.pipeTo(file.writable).finally(
() => file.close(), //TODO: fix bad resource id when closing file
() => file.close() //TODO: fix bad resource id when closing file
);
} catch (error) {
console.error(`ERROR: [downloadFile] ${error.message}`);
Expand Down Expand Up @@ -69,20 +70,7 @@ export class Downloader {
return binaryMap[binaryOs];
}

/**
* Gets download dir
* @returns download dir
*/
private async getDownloadDir(): Promise<string> {
const projectDir = Deno.cwd();
console.log("Project dir:", projectDir);

if (!projectDir) {
throw new Error("Unable to determine the project directory.");
}

const downloadDir = join(projectDir, ".stackql");

private async createDownloadDir(downloadDir: string) {
try {
const stat = await Deno.stat(downloadDir);
if (!stat.isDirectory) {
Expand All @@ -95,6 +83,19 @@ export class Downloader {
throw error;
}
}
}
/**
* Gets download dir
* @returns download dir
*/
private getDownloadDir(): string {
const projectDir = Deno.cwd();

if (!projectDir) {
throw new Error("Unable to determine the project directory.");
}

const downloadDir = join(projectDir, ".stackql");

return downloadDir;
}
Expand All @@ -121,33 +122,68 @@ export class Downloader {
const unpacker = Deno.build.os === "darwin" ? darwinUnpack : unzip;
await unpacker({ downloadDir, archiveFileName });
}

private async setExecutable(binaryPath: string) {
const allowExecOctal = 0o755;
await osUtils.chomod(binaryPath, allowExecOctal);
}

private async downloadAndInstallStackQL({
downloadDir,
binaryName,
}: {
downloadDir: string;
binaryName: string;
}) {
const binaryPath = join(downloadDir, binaryName);
await this.installStackQL(downloadDir);
await this.setExecutable(binaryPath);
return binaryPath;
}
/**
* Setup stackql binary, check if binary exists, if not download it
*/
public async setupStackQL() {
console.log("Installing stackql...");

try {
const binaryName = this.getBinaryName();
const downloadDir = await this.getDownloadDir();
const binaryPath = join(downloadDir, binaryName);
const downloadDir = this.getDownloadDir();
await this.createDownloadDir(downloadDir);

let binaryPath = join(downloadDir, binaryName);

if (this.binaryExists(binaryName, downloadDir)) {
console.log("stackql is already installed");
await this.setExecutable(binaryPath);
return binaryPath;
}

console.log("Downloading stackql binary");
await this.installStackQL(downloadDir);
await this.setExecutable(binaryPath);
binaryPath = await this.downloadAndInstallStackQL({
downloadDir,
binaryName,
});
return binaryPath;
} catch (error) {
console.error(`ERROR: [setup] ${error.message}`);
Deno.exit(1);
}
}

private async removeStackQL() {
const downloadDir = this.getDownloadDir();
await Deno.remove(join(downloadDir, "/"), { recursive: true });
console.log("stackql download dir removed");
}

public async upgradeStackQL() {
if (Deno.build.os === "darwin") {
await this.removeStackQL();
}
const binaryName = this.getBinaryName();
const downloadDir = this.getDownloadDir();
await this.createDownloadDir(downloadDir);
const binaryPath = await this.downloadAndInstallStackQL({
downloadDir,
binaryName,
});
return binaryPath;
}
}
100 changes: 100 additions & 0 deletions src/stackql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,45 @@ Deno.test("Set properties from configs", async () => {
assertSpyCall(runCliSpy, 0, {
args: [binaryPath, ["exec", githubTestQuery, ...params]],
});
runCliSpy.restore();
});

Deno.test("Set proxy properties from configs", async () => {
await setupStackQL();
const runCommandSpy = spy(osUtils, "runCommand");
const stackQL = new StackQL();
await stackQL.initialize({
serverMode: false,
proxyHost: "localhost",
proxyPort: 8080,
proxyUser: "user",
proxyPassword: "password",
proxyScheme: "https",
});
const githubTestQuery =
`SELECT id, name from github.repos.repos where org='stackql'`;

await stackQL.runQuery(githubTestQuery);

const params = stackQL.getParams();
assertEquals(params, [
"--http.proxy.host",
"localhost",
"--http.proxy.port",
"8080",
"--http.proxy.user",
"user",
"--http.proxy.password",
"password",
"--http.proxy.scheme",
"https",
]);
const binaryPath = stackQL.getBinaryPath();
assert(binaryPath);
assertSpyCall(runCommandSpy, 0, {
args: [binaryPath, ["exec", githubTestQuery, ...params]],
});
runCommandSpy.restore();
});

Deno.test("StackQL runServerQuery", async () => {
Expand Down Expand Up @@ -108,3 +147,64 @@ Deno.test("StackQL runServerQuery", async () => {
await stackQL.closeConnection();
}
});

Deno.test("getVersion", async () => {
await setupStackQL();
const stackQL = new StackQL();
await stackQL.initialize({ serverMode: false });
const versionRegex = /^v?(\d+(?:\.\d+)*)$/;
const shaRegex = /^[a-f0-9]{7}$/;

const { version, sha } = await stackQL.getVersion();

assert(version);
assert(sha);
assert(versionRegex.test(version));
assert(shaRegex.test(sha));
});

Deno.test("getVersion when version and sha are undefined", async () => {
await setupStackQL();
const stackQL = new StackQL();
await stackQL.initialize({ serverMode: false });
const versionRegex = /^v?(\d+(?:\.\d+)*)$/;
const shaRegex = /^[a-f0-9]{7}$/;
// deno-lint-ignore no-explicit-any
(stackQL as any).version = undefined;
// deno-lint-ignore no-explicit-any
(stackQL as any).sha = undefined;
// deno-lint-ignore no-explicit-any
assert((stackQL as any).version === undefined);
// deno-lint-ignore no-explicit-any
assert((stackQL as any).sha === undefined);

const { version, sha } = await stackQL.getVersion();

assert(version);
assert(sha);
assert(versionRegex.test(version));
assert(shaRegex.test(sha));
});

Deno.test("upgrade stackql", async () => {
await setupStackQL();
const stackQL = new StackQL();
await stackQL.initialize({ serverMode: false });
// deno-lint-ignore no-explicit-any
(stackQL as any).version = undefined;
// deno-lint-ignore no-explicit-any
(stackQL as any).sha = undefined;
const versionRegex = /^v?(\d+(?:\.\d+)*)$/;
const shaRegex = /^[a-f0-9]{7}$/;
// deno-lint-ignore no-explicit-any
assert((stackQL as any).version === undefined);
// deno-lint-ignore no-explicit-any
assert((stackQL as any).sha === undefined);

const { version, sha } = await stackQL.upgrade();

assert(version);
assert(sha);
assert(versionRegex.test(version));
assert(shaRegex.test(sha));
});
Loading