Skip to content

Commit

Permalink
Fix parsing registry from env variable to work with trailing slash (#748
Browse files Browse the repository at this point in the history
)
  • Loading branch information
ilia-beliaev-miro authored Apr 5, 2024
1 parent 1337e9c commit e56ec2b
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 16 deletions.
149 changes: 137 additions & 12 deletions packages/testcontainers/src/container-runtime/image-name.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,26 @@ describe("ContainerImage", () => {
expect(imageName.string).toBe("aa285b773a2c042056883845aea893a743d358a5d40f61734fa228fde93dae6f:1");
});

it("should substitute no registry with the one provided via TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX", () => {
const oldEnvValue = process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX;
try {
process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = "custom.com/registry";
const imageName = new ImageName(undefined, "image", "tag");
expect(imageName.string).toBe("custom.com/registry/image:tag");
} finally {
if (oldEnvValue === undefined) {
delete process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX;
} else {
process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = oldEnvValue;
it.each(["custom.com/registry", "custom.com/registry/"])(
"should substitute no registry with the one provided via TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX when provided registry is %s",
(customRegistry: string) => {
const oldEnvValue = process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX;
try {
process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = customRegistry;
const imageName = new ImageName(undefined, "image", "tag");
expect(imageName.registry).toBe("custom.com");
expect(imageName.image).toBe("registry/image");
expect(imageName.tag).toBe("tag");
expect(imageName.string).toBe("custom.com/registry/image:tag");
} finally {
if (oldEnvValue === undefined) {
delete process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX;
} else {
process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = oldEnvValue;
}
}
}
});
);
});

describe("fromString", () => {
Expand Down Expand Up @@ -156,4 +162,123 @@ describe("ContainerImage", () => {
expect(imageName.tag).toBe("1");
});
});

describe.each([
{ customRegistry: "custom.com/registry", expectedRegistry: "custom.com", expectedImagePrefix: "registry/" },
{ customRegistry: "custom.com/registry/", expectedRegistry: "custom.com", expectedImagePrefix: "registry/" },
{ customRegistry: "custom.com", expectedRegistry: "custom.com", expectedImagePrefix: "" },
{
customRegistry: "custom.com/registry/with/slashes",
expectedRegistry: "custom.com",
expectedImagePrefix: "registry/with/slashes/",
},
])(
"fromString with TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX set to $customRegistry",
({ customRegistry, expectedRegistry, expectedImagePrefix }) => {
let oldEnvValue: string | undefined;
beforeEach(() => {
oldEnvValue = process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX;
process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = customRegistry;
});

afterEach(() => {
if (oldEnvValue === undefined) {
delete process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX;
} else {
process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = oldEnvValue;
}
});

it("should work", () => {
const imageName = ImageName.fromString("image:latest");

expect(imageName.registry).toEqual(expectedRegistry);
expect(imageName.image).toEqual(`${expectedImagePrefix}image`);
expect(imageName.tag).toBe("latest");
});

it("should work without tag", () => {
const imageName = ImageName.fromString("image");

expect(imageName.registry).toEqual(expectedRegistry);
expect(imageName.image).toEqual(`${expectedImagePrefix}image`);
expect(imageName.tag).toBe("latest");
});

it("should work with registry", () => {
const imageName = ImageName.fromString("domain.com/image:latest");

expect(imageName.registry).toBe("domain.com");
expect(imageName.image).toBe("image");
expect(imageName.tag).toBe("latest");
});

it("should work with registry with port", () => {
const imageName = ImageName.fromString("domain.com:5000/image:latest");

expect(imageName.registry).toBe("domain.com:5000");
expect(imageName.image).toBe("image");
expect(imageName.tag).toBe("latest");
});

it("should work with registry without tag", () => {
const imageName = ImageName.fromString("domain.com/image");

expect(imageName.registry).toBe("domain.com");
expect(imageName.image).toBe("image");
expect(imageName.tag).toBe("latest");
});

it("should work with nested image", () => {
const imageName = ImageName.fromString("parent/child:latest");

expect(imageName.registry).toEqual(expectedRegistry);
expect(imageName.image).toEqual(`${expectedImagePrefix}parent/child`);
expect(imageName.tag).toBe("latest");
});

it("should work with registry and nested image", () => {
const imageName = ImageName.fromString("domain.com/parent/child:latest");

expect(imageName.registry).toBe("domain.com");
expect(imageName.image).toBe("parent/child");
expect(imageName.tag).toBe("latest");
});

it("should work with tag being a hash", () => {
const imageName = ImageName.fromString("image@sha256:1234abcd1234abcd1234abcd1234abcd");

expect(imageName.registry).toEqual(expectedRegistry);
expect(imageName.image).toEqual(`${expectedImagePrefix}image`);
expect(imageName.tag).toBe("sha256:1234abcd1234abcd1234abcd1234abcd");
});

it("should work with image being an image ID", () => {
const imageName = ImageName.fromString("aa285b773a2c042056883845aea893a743d358a5d40f61734fa228fde93dae6f");

expect(imageName.registry).toEqual(expectedRegistry);
expect(imageName.image).toEqual(
`${expectedImagePrefix}aa285b773a2c042056883845aea893a743d358a5d40f61734fa228fde93dae6f`
);
expect(imageName.tag).toBe("latest");
});

it("should work with image being an image ID and an explicit tag", () => {
// Note: Such an ID will not be accepted by docker:
//
// > "invalid repository name [...], cannot specify 64-byte hexadecimal strings"
//
// However, parsing it this way is probably least surprising.
const imageName = ImageName.fromString("aa285b773a2c042056883845aea893a743d358a5d40f61734fa228fde93dae6f:1");

expect(imageName.registry).toEqual(expectedRegistry);
expect(imageName.image).toEqual(
`${expectedImagePrefix}aa285b773a2c042056883845aea893a743d358a5d40f61734fa228fde93dae6f`
);
expect(imageName.tag).toBe("1");
});

// Add more tests here for different scenarios with prefix
}
);
});
20 changes: 16 additions & 4 deletions packages/testcontainers/src/container-runtime/image-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,23 @@ export class ImageName {
public readonly image: string,
public readonly tag: string
) {
if (!this.registry) {
this.registry = process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX;
if (this.registry) {
log.info(`Applying changes to image ${image} with tag ${tag}: added registry ${this.registry}`);
if (!this.registry && process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX) {
const prefix = process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX;

// Parse the registry. If it's undefined - then the whole prefix is a registry.
const registry = ImageName.getRegistry(prefix);
this.registry = registry ?? prefix;

// If the registry is defined, then the imagePrefix is the rest of the prefix.
const imagePrefix = registry ? prefix.substring(prefix.indexOf("/") + 1).replace(/\/?$/, "/") : "";
const originalImage = this.image;
this.image = `${imagePrefix}${this.image}`;

let message = `Applying changes to image ${originalImage} with tag ${tag}: added registry ${this.registry}`;
if (this.image !== originalImage) {
message += ` and changed image to ${this.image}`;
}
log.info(message);
}
if (this.registry) {
if (this.tag.startsWith("sha256:")) {
Expand Down

0 comments on commit e56ec2b

Please sign in to comment.