Files
zopu-code/repos/effect-smol/packages/effect/test/LayerRef.test.ts

132 lines
4.8 KiB
TypeScript

import { assert, describe, it } from "@effect/vitest"
import { Context, Effect, Layer } from "effect"
import * as Exit from "effect/Exit"
import * as LayerRef from "effect/LayerRef"
import * as Scope from "effect/Scope"
class Resource extends Context.Service<Resource, { readonly id: number }>()("LayerRefTest/Resource") {}
const makeLayer = (acquired: Array<number>, released: Array<number>) =>
Layer.effect(Resource)(
Effect.acquireRelease(
Effect.sync(() => {
const id = acquired.length + 1
acquired.push(id)
return { id }
}),
(resource) =>
Effect.sync(() => {
released.push(resource.id)
})
)
)
describe("LayerRef", () => {
it.effect("make lazily acquires and releases resources", () =>
Effect.gen(function*() {
const acquired: Array<number> = []
const released: Array<number> = []
const refScope = yield* Scope.make()
const ref = yield* LayerRef.make(makeLayer(acquired, released)).pipe(Scope.provide(refScope))
assert.deepStrictEqual(acquired, [])
assert.deepStrictEqual(released, [])
const context = yield* Effect.scoped(ref.contextEffect)
assert.strictEqual(Context.get(context, Resource).id, 1)
assert.deepStrictEqual(acquired, [1])
assert.deepStrictEqual(released, [1])
const contextFromLayer = yield* Effect.scoped(Layer.build(ref.get))
assert.strictEqual(Context.get(contextFromLayer, Resource).id, 2)
assert.deepStrictEqual(acquired, [1, 2])
assert.deepStrictEqual(released, [1, 2])
yield* Scope.close(refScope, Exit.void)
assert.deepStrictEqual(released, [1, 2])
}))
it.effect("invalidate releases an idle resource and acquires a fresh one", () =>
Effect.gen(function*() {
const acquired: Array<number> = []
const released: Array<number> = []
const refScope = yield* Scope.make()
const ref = yield* LayerRef.make(makeLayer(acquired, released), {
idleTimeToLive: "1 minute"
}).pipe(Scope.provide(refScope))
const context = yield* Effect.scoped(ref.contextEffect)
assert.strictEqual(Context.get(context, Resource).id, 1)
assert.deepStrictEqual(acquired, [1])
assert.deepStrictEqual(released, [])
const cachedContext = yield* Effect.scoped(ref.contextEffect)
assert.strictEqual(Context.get(cachedContext, Resource).id, 1)
assert.deepStrictEqual(acquired, [1])
assert.deepStrictEqual(released, [])
yield* ref.invalidate
assert.deepStrictEqual(released, [1])
const freshContext = yield* Effect.scoped(ref.contextEffect)
assert.strictEqual(Context.get(freshContext, Resource).id, 2)
assert.deepStrictEqual(acquired, [1, 2])
assert.deepStrictEqual(released, [1])
yield* Scope.close(refScope, Exit.void)
assert.deepStrictEqual(released, [1, 2])
}))
it.effect("preload acquires the resource when the LayerRef is created", () =>
Effect.gen(function*() {
const acquired: Array<number> = []
const released: Array<number> = []
const refScope = yield* Scope.make()
const ref = yield* LayerRef.make(makeLayer(acquired, released), {
idleTimeToLive: "1 minute",
preload: true
}).pipe(Scope.provide(refScope))
assert.deepStrictEqual(acquired, [1])
assert.deepStrictEqual(released, [])
const context = yield* Effect.scoped(ref.contextEffect)
assert.strictEqual(Context.get(context, Resource).id, 1)
assert.deepStrictEqual(acquired, [1])
assert.deepStrictEqual(released, [])
yield* Scope.close(refScope, Exit.void)
assert.deepStrictEqual(released, [1])
}))
it.effect("Service exposes layer, get, contextEffect, and invalidate", () =>
Effect.gen(function*() {
const acquired: Array<number> = []
const released: Array<number> = []
class ResourceRef extends LayerRef.Service<ResourceRef>()("LayerRefTest/ResourceRef", {
layer: makeLayer(acquired, released),
idleTimeToLive: "1 minute"
}) {}
yield* Effect.gen(function*() {
const context = yield* Effect.scoped(ResourceRef.contextEffect)
assert.strictEqual(Context.get(context, Resource).id, 1)
const contextFromLayer = yield* Effect.scoped(Layer.build(ResourceRef.get))
assert.strictEqual(Context.get(contextFromLayer, Resource).id, 1)
assert.deepStrictEqual(acquired, [1])
assert.deepStrictEqual(released, [])
yield* ResourceRef.invalidate
assert.deepStrictEqual(released, [1])
const freshContext = yield* Effect.scoped(ResourceRef.contextEffect)
assert.strictEqual(Context.get(freshContext, Resource).id, 2)
assert.deepStrictEqual(acquired, [1, 2])
}).pipe(Effect.provide(ResourceRef.layer))
assert.deepStrictEqual(released, [1, 2])
}))
})