test: use Effect file services in migrated tests (#27154)
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { describe, expect, beforeAll, afterAll } from "bun:test"
|
import { describe, expect, beforeAll, afterAll } from "bun:test"
|
||||||
import { Effect } from "effect"
|
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||||
|
import { Effect, Layer } from "effect"
|
||||||
import { Discovery } from "../../src/skill/discovery"
|
import { Discovery } from "../../src/skill/discovery"
|
||||||
import { Global } from "@opencode-ai/core/global"
|
import { Global } from "@opencode-ai/core/global"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
import { Filesystem } from "@/util/filesystem"
|
||||||
@@ -13,7 +14,7 @@ let downloadCount = 0
|
|||||||
|
|
||||||
const fixturePath = path.join(import.meta.dir, "../fixture/skills")
|
const fixturePath = path.join(import.meta.dir, "../fixture/skills")
|
||||||
const cacheDir = path.join(Global.Path.cache, "skills")
|
const cacheDir = path.join(Global.Path.cache, "skills")
|
||||||
const it = testEffect(Discovery.defaultLayer)
|
const it = testEffect(Layer.mergeAll(Discovery.defaultLayer, AppFileSystem.defaultLayer))
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await rm(cacheDir, { recursive: true, force: true })
|
await rm(cacheDir, { recursive: true, force: true })
|
||||||
@@ -49,36 +50,37 @@ afterAll(async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("Discovery.pull", () => {
|
describe("Discovery.pull", () => {
|
||||||
const pull = Effect.fn("DiscoveryTest.pull")(function* (url: string) {
|
|
||||||
return yield* Discovery.Service.use((s) => s.pull(url))
|
|
||||||
})
|
|
||||||
|
|
||||||
it.live("downloads skills from cloudflare url", () =>
|
it.live("downloads skills from cloudflare url", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const dirs = yield* pull(CLOUDFLARE_SKILLS_URL)
|
const fsys = yield* AppFileSystem.Service
|
||||||
|
const discovery = yield* Discovery.Service
|
||||||
|
const dirs = yield* discovery.pull(CLOUDFLARE_SKILLS_URL)
|
||||||
expect(dirs.length).toBeGreaterThan(0)
|
expect(dirs.length).toBeGreaterThan(0)
|
||||||
for (const dir of dirs) {
|
for (const dir of dirs) {
|
||||||
expect(dir).toStartWith(cacheDir)
|
expect(dir).toStartWith(cacheDir)
|
||||||
const md = path.join(dir, "SKILL.md")
|
const md = path.join(dir, "SKILL.md")
|
||||||
expect(yield* Effect.promise(() => Filesystem.exists(md))).toBe(true)
|
expect(yield* fsys.existsSafe(md)).toBe(true)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("url without trailing slash works", () =>
|
it.live("url without trailing slash works", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const dirs = yield* pull(CLOUDFLARE_SKILLS_URL.replace(/\/$/, ""))
|
const fsys = yield* AppFileSystem.Service
|
||||||
|
const discovery = yield* Discovery.Service
|
||||||
|
const dirs = yield* discovery.pull(CLOUDFLARE_SKILLS_URL.replace(/\/$/, ""))
|
||||||
expect(dirs.length).toBeGreaterThan(0)
|
expect(dirs.length).toBeGreaterThan(0)
|
||||||
for (const dir of dirs) {
|
for (const dir of dirs) {
|
||||||
const md = path.join(dir, "SKILL.md")
|
const md = path.join(dir, "SKILL.md")
|
||||||
expect(yield* Effect.promise(() => Filesystem.exists(md))).toBe(true)
|
expect(yield* fsys.existsSafe(md)).toBe(true)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("returns empty array for invalid url", () =>
|
it.live("returns empty array for invalid url", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const dirs = yield* pull(`http://localhost:${server.port}/invalid-url/`)
|
const discovery = yield* Discovery.Service
|
||||||
|
const dirs = yield* discovery.pull(`http://localhost:${server.port}/invalid-url/`)
|
||||||
expect(dirs).toEqual([])
|
expect(dirs).toEqual([])
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@@ -86,20 +88,23 @@ describe("Discovery.pull", () => {
|
|||||||
it.live("returns empty array for non-json response", () =>
|
it.live("returns empty array for non-json response", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
// any url not explicitly handled in server returns 404 text "Not Found"
|
// any url not explicitly handled in server returns 404 text "Not Found"
|
||||||
const dirs = yield* pull(`http://localhost:${server.port}/some-other-path/`)
|
const discovery = yield* Discovery.Service
|
||||||
|
const dirs = yield* discovery.pull(`http://localhost:${server.port}/some-other-path/`)
|
||||||
expect(dirs).toEqual([])
|
expect(dirs).toEqual([])
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("downloads reference files alongside SKILL.md", () =>
|
it.live("downloads reference files alongside SKILL.md", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const dirs = yield* pull(CLOUDFLARE_SKILLS_URL)
|
const fsys = yield* AppFileSystem.Service
|
||||||
|
const discovery = yield* Discovery.Service
|
||||||
|
const dirs = yield* discovery.pull(CLOUDFLARE_SKILLS_URL)
|
||||||
// find a skill dir that should have reference files (e.g. agents-sdk)
|
// find a skill dir that should have reference files (e.g. agents-sdk)
|
||||||
const agentsSdk = dirs.find((d) => d.endsWith(path.sep + "agents-sdk"))
|
const agentsSdk = dirs.find((d) => d.endsWith(path.sep + "agents-sdk"))
|
||||||
expect(agentsSdk).toBeDefined()
|
expect(agentsSdk).toBeDefined()
|
||||||
if (agentsSdk) {
|
if (agentsSdk) {
|
||||||
const refs = path.join(agentsSdk, "references")
|
const refs = path.join(agentsSdk, "references")
|
||||||
expect(yield* Effect.promise(() => Filesystem.exists(path.join(agentsSdk, "SKILL.md")))).toBe(true)
|
expect(yield* fsys.existsSafe(path.join(agentsSdk, "SKILL.md"))).toBe(true)
|
||||||
// agents-sdk has reference files per the index
|
// agents-sdk has reference files per the index
|
||||||
const refDir = yield* Effect.promise(() =>
|
const refDir = yield* Effect.promise(() =>
|
||||||
Array.fromAsync(new Bun.Glob("**/*.md").scan({ cwd: refs, onlyFiles: true })),
|
Array.fromAsync(new Bun.Glob("**/*.md").scan({ cwd: refs, onlyFiles: true })),
|
||||||
@@ -114,15 +119,16 @@ describe("Discovery.pull", () => {
|
|||||||
// clear dir and downloadCount
|
// clear dir and downloadCount
|
||||||
yield* Effect.promise(() => rm(cacheDir, { recursive: true, force: true }))
|
yield* Effect.promise(() => rm(cacheDir, { recursive: true, force: true }))
|
||||||
downloadCount = 0
|
downloadCount = 0
|
||||||
|
const discovery = yield* Discovery.Service
|
||||||
|
|
||||||
// first pull to populate cache
|
// first pull to populate cache
|
||||||
const first = yield* pull(CLOUDFLARE_SKILLS_URL)
|
const first = yield* discovery.pull(CLOUDFLARE_SKILLS_URL)
|
||||||
expect(first.length).toBeGreaterThan(0)
|
expect(first.length).toBeGreaterThan(0)
|
||||||
const firstCount = downloadCount
|
const firstCount = downloadCount
|
||||||
expect(firstCount).toBeGreaterThan(0)
|
expect(firstCount).toBeGreaterThan(0)
|
||||||
|
|
||||||
// second pull should return same results from cache
|
// second pull should return same results from cache
|
||||||
const second = yield* pull(CLOUDFLARE_SKILLS_URL)
|
const second = yield* discovery.pull(CLOUDFLARE_SKILLS_URL)
|
||||||
expect(second.length).toBe(first.length)
|
expect(second.length).toBe(first.length)
|
||||||
expect(second.sort()).toEqual(first.sort())
|
expect(second.sort()).toEqual(first.sort())
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { afterEach, expect } from "bun:test"
|
import { afterEach, expect } from "bun:test"
|
||||||
import { $ } from "bun"
|
import { $ } from "bun"
|
||||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||||
|
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Effect, Fiber } from "effect"
|
import { Effect, Fiber, Layer } from "effect"
|
||||||
import { Snapshot } from "../../src/snapshot"
|
import { Snapshot } from "../../src/snapshot"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
|
||||||
import { disposeAllInstances, provideInstance, TestInstance, tmpdirScoped } from "../fixture/fixture"
|
import { disposeAllInstances, provideInstance, TestInstance, tmpdirScoped } from "../fixture/fixture"
|
||||||
import { testEffect } from "../lib/effect"
|
import { testEffect } from "../lib/effect"
|
||||||
|
|
||||||
const it = testEffect(Snapshot.defaultLayer)
|
const it = testEffect(Layer.mergeAll(Snapshot.defaultLayer, AppFileSystem.defaultLayer))
|
||||||
|
|
||||||
// Git always outputs /-separated paths internally. Snapshot.patch() joins them
|
// Git always outputs /-separated paths internally. Snapshot.patch() joins them
|
||||||
// with path.join (which produces \ on Windows) then normalizes back to /.
|
// with path.join (which produces \ on Windows) then normalizes back to /.
|
||||||
@@ -27,17 +27,13 @@ const exec = (cwd: string, command: string[]) =>
|
|||||||
if (code !== 0) throw new Error(`${command.join(" ")} failed: ${await new Response(proc.stderr).text()}`)
|
if (code !== 0) throw new Error(`${command.join(" ")} failed: ${await new Response(proc.stderr).text()}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
const write = (file: string, content: string | Uint8Array) => Effect.promise(() => Filesystem.write(file, content))
|
const write = (file: string, content: string | Uint8Array) =>
|
||||||
const readText = (file: string) => Effect.promise(() => fs.readFile(file, "utf-8"))
|
AppFileSystem.Service.use((fs) => fs.writeWithDirs(file, content))
|
||||||
const exists = (file: string) =>
|
const readText = (file: string) => AppFileSystem.Service.use((fs) => fs.readFileString(file))
|
||||||
Effect.promise(() =>
|
const exists = (file: string) => AppFileSystem.Service.use((fs) => fs.existsSafe(file))
|
||||||
fs
|
const mkdirp = (dir: string) => AppFileSystem.Service.use((fs) => fs.ensureDir(dir))
|
||||||
.access(file)
|
const rm = (file: string) =>
|
||||||
.then(() => true)
|
AppFileSystem.Service.use((fs) => fs.remove(file, { recursive: true, force: true }).pipe(Effect.ignore))
|
||||||
.catch(() => false),
|
|
||||||
)
|
|
||||||
const mkdirp = (dir: string) => Effect.promise(() => fs.mkdir(dir, { recursive: true }))
|
|
||||||
const rm = (file: string) => Effect.promise(() => fs.rm(file, { recursive: true, force: true }))
|
|
||||||
|
|
||||||
const initialize = Effect.fn("SnapshotTest.initialize")(function* (dir: string) {
|
const initialize = Effect.fn("SnapshotTest.initialize")(function* (dir: string) {
|
||||||
const unique = Math.random().toString(36).slice(2)
|
const unique = Math.random().toString(36).slice(2)
|
||||||
|
|||||||
Reference in New Issue
Block a user