<?php
declare(strict_types=1);require __DIR__.'/bootstrap.php';
$journal=$runtime.'/private-journal.json';$recovery=getenv('SIGN_RECOVER')==='1';$check($recovery===is_file($journal),'No automatic write replay');if($recovery){$old=json_decode(file_get_contents($journal),true);$check($old['cases']===[]&&$old['owned']===[],'Only exact pre-business tool recovery');copy($journal,$runtime.'/private-harness-red-journal.json');copy($runtime.'/private-report.json',$runtime.'/private-harness-red-report.json');$cache->clear();}$before=$snapshot();$cases=[];$errors=[];$owned=[];$tokens=[];$stats=[];$collections=[];
$save=static function()use($journal,&$cases,&$errors,&$owned,&$stats,&$collections,$before,$boundary){file_put_contents($journal,json_encode(['lane'=>getenv('SIGN_LANE'),'before'=>$before,'boundary'=>$boundary,'cases'=>$cases,'errors'=>$errors,'owned'=>$owned,'cli_stats'=>$stats,'collections'=>$collections],JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION));chmod($journal,0600);};$save();
$quote=static function($s)use($dm){return $dm?'"'.strtoupper($s).'"':'`'.$s.'`';};$insert=$db->prepare('INSERT INTO yoshop_store_setting ('.$quote('key').','.$quote('describe').','.$quote('values').',store_id,create_time,update_time) VALUES (?,?,?,?,?,?)');foreach($tenants as $module=>$tenant){if($recovery){$s=$q('SELECT * FROM yoshop_store_setting WHERE store_id=?',[$tenant]);$check(count($s)===1&&$s[0]['describe']==='本地二维码验收 '.$marker&&json_decode($s[0]['values'],true)===['default'=>'local','engine'=>['local'=>null]],'Exact own storage recovery');}else{$check((int)$q('SELECT COUNT(*) n FROM yoshop_store_setting WHERE store_id=?',[$tenant])[0]['n']===0,'Live own storage collision');$insert->execute(['storage','本地二维码验收 '.$marker,json_encode(['default'=>'local','engine'=>['local'=>null]]),$tenant,time(),time()]);}$tokens[$module]=bin2hex(random_bytes(24));$cache->set($tokens[$module],['user'=>['store_user_id'=>$tenant,'store_id'=>$tenant,'real_name'=>$marker,'user_name'=>$marker,'is_super'=>1],'store_id'=>$tenant,'is_login'=>true],3600);}$save();
$req=static function($module,$name,$action,$params=[],$expected=200,$message=null,$auth=true)use($runtime,$base,$tokens,$check,$save,$own,&$cases,&$collections,&$stats){$scenario=(getenv('SIGN_RECOVER')==='1'?'PILOT_SG_R_':'PILOT_SG_').strtoupper($module.'_'.$name);$method=in_array($action,['list','detail'],true)?'GET':'POST';$headers=[['key'=>'Host','value'=>$module.'.sign-config.invalid'],['key'=>'Platform','value'=>'POC'],['key'=>'X-Pilot-Scenario','value'=>$scenario]];if($auth)$headers[]=['key'=>'Access-Token','value'=>$tokens[$module]];$url=$base.'/'.$module.'/market.sign/'.$action;if($method==='GET')$url.='?'.http_build_query($params);else $headers[]=['key'=>'Content-Type','value'=>'application/json'];$request=['method'=>$method,'url'=>$url,'header'=>$headers];if($method==='POST')$request['body']=['mode'=>'raw','raw'=>json_encode($params,JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION),'options'=>['raw'=>['language'=>'json']]];
$tests=["pm.test('HTTP 200',function(){pm.response.to.have.status(200);});var b=pm.response.json();","pm.test('Numeric business status',function(){pm.expect(b.status).to.eql(".$expected.");});","pm.test('Trace contract',function(){pm.expect(b.trace_id).to.match(/^[0-9a-f]{13}$/);});","pm.test('Message and data types',function(){pm.expect(typeof b.message).to.eql('string');pm.expect(typeof b.data).to.eql('object');});"];if($message!==null)$tests[]="pm.test('Exact message',function(){pm.expect(b.message).to.eql(".json_encode($message,JSON_UNESCAPED_UNICODE).");});";
$item=['id'=>$scenario,'name'=>$module.' '.$name,'type'=>'http','metaInfo'=>['type'=>'HTTP'],'request'=>$request,'event'=>[['listen'=>'test','script'=>['type'=>'text/javascript','exec'=>$tests]]]];$col=['apifoxCli'=>'2.2.8','info'=>['name'=>'智慧餐厅Sign配置原生请求'],'item'=>[['name'=>'Sign场景','item'=>[$item]]]];$path=$runtime.'/private-request.json';file_put_contents($path,json_encode($col,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));chmod($path,0600);$dir=$runtime.'/private-cli-report/'.$scenario;mkdir($dir,0700,true);$start=time();$p=proc_open(['node',getenv('SIGN_CLI'),'run',$path,'-r','json','--out-dir',$dir,'--out-file','result','--on-error','end','--timeout-request','30000','--silent'],[0=>['file','/dev/null','r'],1=>['file',$runtime.'/private-cli.log','a'],2=>['file',$runtime.'/private-cli.log','a']],$pipes);$exit=proc_close($p);$end=time();$wire=null;foreach(file($runtime.'/private-wire.jsonl',FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES)?:[] as $l){$w=json_decode($l,true);if($w['scenario']===$scenario)$wire=$w;}$check($wire!==null,'Native raw capture '.$scenario);$body=json_decode($wire['raw']);$read=$own();$case=['scenario'=>$scenario,'module'=>$module,'action'=>$action,'method'=>$method,'path'=>'/'.$module.'/market.Sign/'.$action,'wire_path'=>$wire['path'],'http_status'=>$wire['http_status'],'body'=>$body,'raw_sha256'=>hash('sha256',$wire['raw']),'window'=>[$start,$end],'native_cli_exit'=>$exit,'params'=>$params,'independent_original'=>$read,'expected_status'=>$expected,'expected_message'=>$message];$cases[]=$case;$collections[]=$col;foreach(glob($dir.'/*.json') as $f){$report=json_decode(file_get_contents($f),true);if(isset($report['run']))$stats[]=['scenario'=>$scenario,'stats'=>$report['run']['stats'],'failures'=>count($report['run']['failures']??[]),'raw_report_sha256'=>hash_file('sha256',$f)];}$save();return $case;};
foreach($tenants as $module=>$tenant){try{$req($module,'AUTH','list',[],401,null,false);$req($module,'EMPTY','list');$req($module,'REQUIRED_TITLE','add',['form'=>[]],500,'活动名称不能为空');$form=['title'=>'城市骑行活动 '.$marker.' '.$module,'cover_img_id'=>0,'rule_img_id'=>0,'start_time'=>'2026-10-20 08:30:00','end_time'=>'2026-10-21 17:45:00','status'=>2,'addressList'=>[['address'=>'东门集合点 '.$marker],['address'=>'文化广场 '.$marker]]];$c=$req($module,'ADD','add',['form'=>$form]);$rows=$q('SELECT * FROM yoshop_sign_action WHERE store_id=? ORDER BY id',[$tenant]);$check(count($rows)===1&&$rows[0]['title']===$form['title'],'Actual own added row');$id=(int)$rows[0]['id'];$owned[$module]=$id;$save();$req($module,'DETAIL','detail',['signId'=>$id]);$req($module,'LIST','list',['search'=>$marker]);$a=$q('SELECT * FROM yoshop_sign_address WHERE action_id=? ORDER BY id',[$id]);$check(count($a)===2,'Two own address rows');$form['title']='城市骑行复核 '.$marker.' '.$module;$form['status']=1;$form['addressList']=[['id'=>(int)$a[0]['id'],'address'=>'东门出发点 '.$marker],['id'=>(int)$a[1]['id'],'address'=>'文化广场复核 '.$marker]];$req($module,'EDIT','edit',['signId'=>$id,'form'=>$form]);$req($module,'DETAIL_EDITED','detail',['signId'=>$id]);$req($module,'SEARCH_MISS','list',['search'=>'NO_MATCH_'.$marker]);$other=$module==='store'?'terminal':'store';if(isset($owned[$other])){$req($module,'TENANT_DETAIL','detail',['signId'=>$owned[$other]],500,'打卡活动不存在');$req($module,'TENANT_DELETE','delete',['signId'=>$owned[$other]],500,'打卡活动不存在');}$req($module,'DELETE','delete',['signId'=>$id]);$req($module,'LIST_DELETED','list',['search'=>$marker]);$req($module,'DETAIL_DELETED','detail',['signId'=>$id]);$req($module,'MISSING_DETAIL','detail',['signId'=>2147001599],500,'打卡活动不存在');$req($module,'MISSING_EDIT','edit',['signId'=>2147001599,'form'=>$form],500,'打卡活动不存在');$req($module,'MISSING_DELETE','delete',['signId'=>2147001599],500,'打卡活动不存在');}catch(Throwable $e){$errors[]=['module'=>$module,'message'=>$e->getMessage()];$save();}}
$after=$snapshot();$report=['lane'=>$lane,'before'=>$before,'after'=>$after,'protected_unchanged'=>$before===$after,'cases'=>$cases,'errors'=>$errors,'owned'=>$owned,'cli_stats'=>$stats,'boundary'=>$boundary,'final_original'=>$own()];file_put_contents($runtime.'/private-report.json',json_encode($report,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION));chmod($runtime.'/private-report.json',0600);$save();echo json_encode(['lane'=>$lane,'requests'=>count($cases),'cli_failures'=>array_sum(array_column($stats,'failures')),'errors'=>$errors,'owned'=>$owned,'protected_unchanged'=>$before===$after]),"\n";
