@mytmpvpn/mytmpvpn-client
Version:
MyTmpVpn Client Library
154 lines (153 loc) • 8.3 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const fc = __importStar(require("fast-check"));
const appconfig = __importStar(require("../src/appconfig"));
const src_1 = require("../src");
const location_1 = require("@mytmpvpn/mytmpvpn-common/models/location");
describe('Testing regions related APIs', () => {
const appConfig = appconfig.loadDefaultAppConfig();
const client = (0, src_1.getClientModule)(appConfig.apiUrl);
it("should list all locations", async () => {
const locations = await client.listLocations();
expect(locations).toBeDefined();
// dev, gamma, prod all have more than 3 regions
expect(Object.keys(locations).length).toBeGreaterThanOrEqual(3);
locations.forEach((location) => {
expect(location).toBeDefined();
expect(location.geonamesId).toBeGreaterThan(0);
expect(location.city.length).toBeGreaterThan(0);
expect(location.country.length).toBeGreaterThan(0);
expect(location.countryCode.length).toBeGreaterThan(0);
expect(location.coordinates).toBeDefined();
expect(location.coordinates.latitude).toBeDefined();
expect(location.coordinates.longitude).toBeDefined();
expect(location.providersInfo).toBeDefined();
const providersInfo = location.providersInfo;
expect(providersInfo.Aws).toBeDefined();
expect(providersInfo.Aws?.infraDetails).toBeDefined();
expect(providersInfo.Aws?.infraDetails.ipv6Supported).toBeDefined();
const pricingRates = providersInfo.Aws?.pricingRates;
const instanceTypes = Object.keys(pricingRates);
// There should be at least one
expect(instanceTypes.length).toBeGreaterThan(0);
instanceTypes.forEach(instanceType => {
expect(pricingRates[instanceType]).toBeDefined();
expect(pricingRates[instanceType].peanutsPerMinuteMax).toBeGreaterThan(0);
expect(pricingRates[instanceType].peanutsPerMinuteMin).toBeGreaterThan(0);
});
});
});
});
// --- Property-Based Test: Property 5 ---
// Arbitrary: generates a valid PricingRate with non-negative values
const arbPricingRate = fc.record({
peanutsPerMinuteMin: fc.double({ min: 0, max: 1000, noNaN: true, noDefaultInfinity: true }),
peanutsPerMinuteMax: fc.double({ min: 0, max: 1000, noNaN: true, noDefaultInfinity: true }),
});
// All valid instance types and infrastructure providers
const allInstanceTypes = Object.values(location_1.InstanceType);
const allProviders = Object.values(location_1.InfrastructureProvider);
// Arbitrary: generates a non-empty subset of InstanceType values
const arbInstanceTypeSubset = fc
.subarray(allInstanceTypes, { minLength: 1 });
// Arbitrary: generates a random InfrastructureProvider
const arbProvider = fc.constantFrom(...allProviders);
// Arbitrary: generates a non-empty subset of providers
const arbProviderSubset = fc
.subarray(allProviders, { minLength: 1 });
// Arbitrary: generates a ProviderInfo with a random non-empty subset of instance types in pricingRates
const arbProviderInfo = arbInstanceTypeSubset
.chain((instanceTypes) => {
const pricingEntries = instanceTypes.map((it) => arbPricingRate.map((rate) => [it, rate]));
return fc.tuple(...pricingEntries).map((entries) => {
const pricingRates = {};
for (const [it, rate] of entries) {
pricingRates[it] = rate;
}
return pricingRates;
});
})
.map((pricingRates) => ({
infraDetails: { ipv6Supported: fc.sample(fc.boolean(), 1)[0] },
pricingRates,
}));
// Arbitrary: generates a LocationWithProvidersInfo with random providers, each having random instance types
const arbLocationWithProviders = arbProviderSubset
.chain((providers) => {
const providerEntries = providers.map((provider) => arbProviderInfo.map((info) => [provider, info]));
return fc.tuple(...providerEntries).map((entries) => {
const providersInfo = {};
for (const [provider, info] of entries) {
providersInfo[provider] = info;
}
return providersInfo;
});
})
.chain((providersInfo) => fc.tuple(fc.integer({ min: 1, max: 999999 }), fc.string({ minLength: 1, maxLength: 20 }), fc.string({ minLength: 1, maxLength: 20 }), fc.tuple(fc.constantFrom('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'), fc.constantFrom('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z')).map(([a, b]) => `${a}${b}`), fc.double({ min: -90, max: 90, noNaN: true, noDefaultInfinity: true }), fc.double({ min: -180, max: 180, noNaN: true, noDefaultInfinity: true })).map(([geonamesId, city, country, countryCode, lat, lon]) => ({
geonamesId,
city,
country,
countryCode,
coordinates: { latitude: lat, longitude: lon },
providersInfo,
})));
describe('Feature: frontend-instance-type-pricing, Property 5: List-locations output contains pricing rates for all instance types', () => {
/**
* **Validates: Requirements 8.1, 8.2**
*
* For any location, each provider in providersInfo should have a pricingRates object
* containing at least one InstanceType key with a valid PricingRate
* (both peanutsPerMinuteMin and peanutsPerMinuteMax are non-negative numbers).
*/
it('should have pricingRates with at least one InstanceType key containing valid PricingRate values for each provider', () => {
fc.assert(fc.property(arbLocationWithProviders, (location) => {
const providers = Object.keys(location.providersInfo);
// Location must have at least one provider
expect(providers.length).toBeGreaterThan(0);
for (const provider of providers) {
const providerInfo = location.providersInfo[provider];
expect(providerInfo).toBeDefined();
const pricingRates = providerInfo.pricingRates;
expect(pricingRates).toBeDefined();
const instanceTypeKeys = Object.keys(pricingRates);
// Each provider must have at least one instance type in pricingRates
expect(instanceTypeKeys.length).toBeGreaterThan(0);
for (const instanceType of instanceTypeKeys) {
// Each key must be a valid InstanceType enum value
expect(allInstanceTypes).toContain(instanceType);
const rate = pricingRates[instanceType];
expect(rate).toBeDefined();
// peanutsPerMinuteMin must be a non-negative number
expect(typeof rate.peanutsPerMinuteMin).toBe('number');
expect(rate.peanutsPerMinuteMin).toBeGreaterThanOrEqual(0);
// peanutsPerMinuteMax must be a non-negative number
expect(typeof rate.peanutsPerMinuteMax).toBe('number');
expect(rate.peanutsPerMinuteMax).toBeGreaterThanOrEqual(0);
}
}
}), { numRuns: 100 });
});
});