// META: timeout=long // META: title=validation tests for WebNN API MLContext::destroy() // META: global=window,worker // META: variant=?cpu // META: variant=?gpu // META: variant=?npu 'use strict'; let contextOptions; promise_setup(async () => { if (navigator.ml === undefined) { return; } contextOptions = {deviceType: location.search.substring(1)}; }, {explicit_timeout: true}); promise_test(async t => { const context = await navigator.ml.createContext(contextOptions); context.destroy(); await context.lost; }, 'Context will be lost by destroyed.'); promise_test(async t => { const context = await navigator.ml.createContext(contextOptions); context.destroy(); context.destroy(); await context.lost; }, 'Context can be destroyed twice.'); promise_test(async t => { const context = await navigator.ml.createContext(contextOptions); const builder = new MLGraphBuilder(context); context.destroy(); assert_throws_dom('InvalidStateError', () => { const operandType = {dataType: 'float32', shape: [1]}; builder.input('input', operandType); }); }, 'Destroyed context can not build operator.'); promise_test(async t => { const context = await navigator.ml.createContext(contextOptions); context.destroy(); assert_throws_dom('InvalidStateError', () => { new MLGraphBuilder(context); }); }, 'Destroyed context can not create graph builder.'); promise_test(async t => { const context = await navigator.ml.createContext(contextOptions); const builder = new MLGraphBuilder(context); const operandType = {dataType: 'float32', shape: [1]}; const input_operand = builder.input('input', operandType); const const_operand = builder.constant(operandType, Float32Array.from([2])); const output_operand = builder.mul(input_operand, const_operand); context.destroy(); promise_rejects_dom( t, 'InvalidStateError', builder.build({'output': output_operand})); }, 'Destroyed context can not build graph.'); promise_test(async t => { const context = await navigator.ml.createContext(contextOptions); const builder = new MLGraphBuilder(context); const operandType = {dataType: 'float32', shape: [1]}; const lhsOperand = builder.input('lhs', operandType); const rhsOperand = builder.input('rhs', operandType); const graph = await builder.build({'output': builder.sub(lhsOperand, rhsOperand)}); const lhsTensor = await context.createTensor(operandType); const rhsTensor = await context.createTensor(operandType); const dispatchOutputs = {'output': await context.createTensor(operandType)}; context.destroy(); assert_throws_dom('InvalidStateError', () => { context.dispatch( graph, { 'lhs': lhsTensor, 'rhs': rhsTensor, }, dispatchOutputs); }); }, 'Destroyed context can not dispatch.'); promise_test(async t => { const context = await navigator.ml.createContext(contextOptions); const builder = new MLGraphBuilder(context); const operandType = {dataType: 'float32', shape: [1]}; const lhsOperand = builder.input('lhs', operandType); const rhsOperand = builder.input('rhs', operandType); const graph = await builder.build({'output': builder.sub(lhsOperand, rhsOperand)}); const lhsTensor = await context.createTensor(operandType); const rhsTensor = await context.createTensor(operandType); const dispatchOutputs = {'output': await context.createTensor(operandType)}; context.dispatch( graph, { 'lhs': lhsTensor, 'rhs': rhsTensor, }, dispatchOutputs); context.destroy(); }, 'Executing dispatch() before context destroyed is OK.'); promise_test(async t => { const context = await navigator.ml.createContext(contextOptions); context.destroy(); promise_rejects_dom( t, 'InvalidStateError', context.createTensor({dataType: 'float32', shape: [1]})); }, 'Destroyed context can not create tensor.'); promise_test(async t => { const context = await navigator.ml.createContext(contextOptions); const tensor = await context.createTensor({ dataType: 'float32', shape: [1], readable: true, }); context.destroy(); promise_rejects_dom(t, 'InvalidStateError', context.readTensor(tensor)); }, 'Destroyed context can not read tensor.'); promise_test(async t => { const context = await navigator.ml.createContext(contextOptions); const tensor = await context.createTensor({ dataType: 'float32', shape: [1], readable: true, }); let promise = context.readTensor(tensor); context.destroy(); promise_rejects_dom(t, 'InvalidStateError', promise); }, 'Pending promise of readtensor() will be rejected immediately when context is destroyed.'); promise_test(async t => { const context = await navigator.ml.createContext(contextOptions); // Destroying another context doesn't impact the first context. const another_context = await navigator.ml.createContext(contextOptions); another_context.destroy(); const tensor = await context.createTensor({ dataType: 'float32', shape: [1], writable: true, }); let arrayBuffer = new ArrayBuffer(4); context.destroy(); assert_throws_dom('InvalidStateError', () => { context.writeTensor(tensor, new Uint8Array(arrayBuffer)); }); }, 'Destroyed context can not write tensor.');