| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203 |
- package common
- import (
- "encoding/json"
- "fmt"
- "reflect"
- "testing"
- common2 "github.com/QuantumNous/new-api/common"
- "github.com/QuantumNous/new-api/types"
- "github.com/QuantumNous/new-api/dto"
- "github.com/QuantumNous/new-api/setting/model_setting"
- "github.com/samber/lo"
- )
- func TestApplyParamOverrideTrimPrefix(t *testing.T) {
- // trim_prefix example:
- // {"operations":[{"path":"model","mode":"trim_prefix","value":"openai/"}]}
- input := []byte(`{"model":"openai/gpt-4","temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "trim_prefix",
- "value": "openai/",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
- }
- func TestApplyParamOverrideTrimSuffix(t *testing.T) {
- // trim_suffix example:
- // {"operations":[{"path":"model","mode":"trim_suffix","value":"-latest"}]}
- input := []byte(`{"model":"gpt-4-latest","temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "trim_suffix",
- "value": "-latest",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
- }
- func TestApplyParamOverrideTrimNoop(t *testing.T) {
- // trim_prefix no-op example:
- // {"operations":[{"path":"model","mode":"trim_prefix","value":"openai/"}]}
- input := []byte(`{"model":"gpt-4","temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "trim_prefix",
- "value": "openai/",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
- }
- func TestApplyParamOverrideMixedLegacyAndOperations(t *testing.T) {
- input := []byte(`{"model":"openai/gpt-4","temperature":0.7}`)
- override := map[string]interface{}{
- "temperature": 0.2,
- "top_p": 0.95,
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "trim_prefix",
- "value": "openai/",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","temperature":0.2,"top_p":0.95}`, string(out))
- }
- func TestApplyParamOverrideMixedLegacyAndOperationsConflictPrefersOperations(t *testing.T) {
- input := []byte(`{"model":"openai/gpt-4","temperature":0.7}`)
- override := map[string]interface{}{
- "model": "legacy-model",
- "temperature": 0.2,
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "set",
- "value": "op-model",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"op-model","temperature":0.2}`, string(out))
- }
- func TestApplyParamOverrideTrimRequiresValue(t *testing.T) {
- // trim_prefix requires value example:
- // {"operations":[{"path":"model","mode":"trim_prefix"}]}
- input := []byte(`{"model":"gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "trim_prefix",
- },
- },
- }
- _, err := ApplyParamOverride(input, override, nil)
- if err == nil {
- t.Fatalf("expected error, got nil")
- }
- }
- func TestApplyParamOverrideReplace(t *testing.T) {
- // replace example:
- // {"operations":[{"path":"model","mode":"replace","from":"openai/","to":""}]}
- input := []byte(`{"model":"openai/gpt-4o-mini","temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "replace",
- "from": "openai/",
- "to": "",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4o-mini","temperature":0.7}`, string(out))
- }
- func TestApplyParamOverrideRegexReplace(t *testing.T) {
- // regex_replace example:
- // {"operations":[{"path":"model","mode":"regex_replace","from":"^gpt-","to":"openai/gpt-"}]}
- input := []byte(`{"model":"gpt-4o-mini","temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "regex_replace",
- "from": "^gpt-",
- "to": "openai/gpt-",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"openai/gpt-4o-mini","temperature":0.7}`, string(out))
- }
- func TestApplyParamOverrideReplaceRequiresFrom(t *testing.T) {
- // replace requires from example:
- // {"operations":[{"path":"model","mode":"replace"}]}
- input := []byte(`{"model":"gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "replace",
- },
- },
- }
- _, err := ApplyParamOverride(input, override, nil)
- if err == nil {
- t.Fatalf("expected error, got nil")
- }
- }
- func TestApplyParamOverrideRegexReplaceRequiresPattern(t *testing.T) {
- // regex_replace requires from(pattern) example:
- // {"operations":[{"path":"model","mode":"regex_replace"}]}
- input := []byte(`{"model":"gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "regex_replace",
- },
- },
- }
- _, err := ApplyParamOverride(input, override, nil)
- if err == nil {
- t.Fatalf("expected error, got nil")
- }
- }
- func TestApplyParamOverrideDelete(t *testing.T) {
- input := []byte(`{"model":"gpt-4","temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "temperature",
- "mode": "delete",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- var got map[string]interface{}
- if err := json.Unmarshal(out, &got); err != nil {
- t.Fatalf("failed to unmarshal output JSON: %v", err)
- }
- if _, exists := got["temperature"]; exists {
- t.Fatalf("expected temperature to be deleted")
- }
- }
- func TestApplyParamOverrideDeleteWildcardPath(t *testing.T) {
- input := []byte(`{"tools":[{"type":"bash","custom":{"input_examples":["a"],"other":1}},{"type":"code","custom":{"input_examples":["b"]}},{"type":"noop","custom":{"other":2}}]}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "tools.*.custom.input_examples",
- "mode": "delete",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"tools":[{"type":"bash","custom":{"other":1}},{"type":"code","custom":{}},{"type":"noop","custom":{"other":2}}]}`, string(out))
- }
- func TestApplyParamOverrideSetWildcardPath(t *testing.T) {
- input := []byte(`{"tools":[{"custom":{"tag":"A"}},{"custom":{"tag":"B"}},{"custom":{"tag":"C"}}]}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "tools.*.custom.enabled",
- "mode": "set",
- "value": true,
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- var got struct {
- Tools []struct {
- Custom struct {
- Enabled bool `json:"enabled"`
- } `json:"custom"`
- } `json:"tools"`
- }
- if err := json.Unmarshal(out, &got); err != nil {
- t.Fatalf("failed to unmarshal output JSON: %v", err)
- }
- if !lo.EveryBy(got.Tools, func(item struct {
- Custom struct {
- Enabled bool `json:"enabled"`
- } `json:"custom"`
- }) bool {
- return item.Custom.Enabled
- }) {
- t.Fatalf("expected wildcard set to enable all tools, got: %s", string(out))
- }
- }
- func TestApplyParamOverrideTrimSpaceWildcardPath(t *testing.T) {
- input := []byte(`{"tools":[{"custom":{"name":" alpha "}},{"custom":{"name":" beta"}},{"custom":{"name":"gamma "}}]}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "tools.*.custom.name",
- "mode": "trim_space",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- var got struct {
- Tools []struct {
- Custom struct {
- Name string `json:"name"`
- } `json:"custom"`
- } `json:"tools"`
- }
- if err := json.Unmarshal(out, &got); err != nil {
- t.Fatalf("failed to unmarshal output JSON: %v", err)
- }
- names := lo.Map(got.Tools, func(item struct {
- Custom struct {
- Name string `json:"name"`
- } `json:"custom"`
- }, _ int) string {
- return item.Custom.Name
- })
- if !reflect.DeepEqual(names, []string{"alpha", "beta", "gamma"}) {
- t.Fatalf("unexpected names after wildcard trim_space: %v", names)
- }
- }
- func TestApplyParamOverrideDeleteWildcardEqualsIndexedPaths(t *testing.T) {
- input := []byte(`{"tools":[{"custom":{"input_examples":["a"],"other":1}},{"custom":{"input_examples":["b"],"other":2}},{"custom":{"input_examples":["c"],"other":3}}]}`)
- wildcardOverride := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "tools.*.custom.input_examples",
- "mode": "delete",
- },
- },
- }
- indexedOverride := map[string]interface{}{
- "operations": lo.Map(lo.Range(3), func(index int, _ int) interface{} {
- return map[string]interface{}{
- "path": fmt.Sprintf("tools.%d.custom.input_examples", index),
- "mode": "delete",
- }
- }),
- }
- wildcardOut, err := ApplyParamOverride(input, wildcardOverride, nil)
- if err != nil {
- t.Fatalf("wildcard ApplyParamOverride returned error: %v", err)
- }
- indexedOut, err := ApplyParamOverride(input, indexedOverride, nil)
- if err != nil {
- t.Fatalf("indexed ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, string(indexedOut), string(wildcardOut))
- }
- func TestApplyParamOverrideSetWildcardKeepOrigin(t *testing.T) {
- input := []byte(`{"tools":[{"custom":{"tag":"A"}},{"custom":{"tag":"B","enabled":false}},{"custom":{"tag":"C"}}]}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "tools.*.custom.enabled",
- "mode": "set",
- "value": true,
- "keep_origin": true,
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- var got struct {
- Tools []struct {
- Custom struct {
- Enabled bool `json:"enabled"`
- } `json:"custom"`
- } `json:"tools"`
- }
- if err := json.Unmarshal(out, &got); err != nil {
- t.Fatalf("failed to unmarshal output JSON: %v", err)
- }
- enabledValues := lo.Map(got.Tools, func(item struct {
- Custom struct {
- Enabled bool `json:"enabled"`
- } `json:"custom"`
- }, _ int) bool {
- return item.Custom.Enabled
- })
- if !reflect.DeepEqual(enabledValues, []bool{true, false, true}) {
- t.Fatalf("unexpected enabled values after wildcard keep_origin set: %v", enabledValues)
- }
- }
- func TestApplyParamOverrideTrimSpaceMultiWildcardPath(t *testing.T) {
- input := []byte(`{"tools":[{"custom":{"items":[{"name":" alpha "},{"name":" beta "}]}},{"custom":{"items":[{"name":" gamma"}]}}]}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "tools.*.custom.items.*.name",
- "mode": "trim_space",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- var got struct {
- Tools []struct {
- Custom struct {
- Items []struct {
- Name string `json:"name"`
- } `json:"items"`
- } `json:"custom"`
- } `json:"tools"`
- }
- if err := json.Unmarshal(out, &got); err != nil {
- t.Fatalf("failed to unmarshal output JSON: %v", err)
- }
- names := lo.FlatMap(got.Tools, func(tool struct {
- Custom struct {
- Items []struct {
- Name string `json:"name"`
- } `json:"items"`
- } `json:"custom"`
- }, _ int) []string {
- return lo.Map(tool.Custom.Items, func(item struct {
- Name string `json:"name"`
- }, _ int) string {
- return item.Name
- })
- })
- if !reflect.DeepEqual(names, []string{"alpha", "beta", "gamma"}) {
- t.Fatalf("unexpected names after multi wildcard trim_space: %v", names)
- }
- }
- func TestApplyParamOverrideSet(t *testing.T) {
- input := []byte(`{"model":"gpt-4","temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(out))
- }
- func TestApplyParamOverrideSetWithDescriptionKeepsCompatibility(t *testing.T) {
- input := []byte(`{"model":"gpt-4","temperature":0.7}`)
- overrideWithoutDesc := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- },
- },
- }
- overrideWithDesc := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "description": "set temperature for deterministic output",
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- },
- },
- }
- outWithoutDesc, err := ApplyParamOverride(input, overrideWithoutDesc, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride without description returned error: %v", err)
- }
- outWithDesc, err := ApplyParamOverride(input, overrideWithDesc, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride with description returned error: %v", err)
- }
- assertJSONEqual(t, string(outWithoutDesc), string(outWithDesc))
- assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(outWithDesc))
- }
- func TestApplyParamOverrideSetKeepOrigin(t *testing.T) {
- input := []byte(`{"model":"gpt-4","temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- "keep_origin": true,
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
- }
- func TestApplyParamOverrideMove(t *testing.T) {
- input := []byte(`{"model":"gpt-4","meta":{"x":1}}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "move",
- "from": "model",
- "to": "meta.model",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"meta":{"x":1,"model":"gpt-4"}}`, string(out))
- }
- func TestApplyParamOverrideMoveMissingSource(t *testing.T) {
- input := []byte(`{"meta":{"x":1}}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "move",
- "from": "model",
- "to": "meta.model",
- },
- },
- }
- _, err := ApplyParamOverride(input, override, nil)
- if err == nil {
- t.Fatalf("expected error, got nil")
- }
- }
- func TestApplyParamOverridePrependAppendString(t *testing.T) {
- input := []byte(`{"model":"gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "prepend",
- "value": "openai/",
- },
- map[string]interface{}{
- "path": "model",
- "mode": "append",
- "value": "-latest",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"openai/gpt-4-latest"}`, string(out))
- }
- func TestApplyParamOverridePrependAppendArray(t *testing.T) {
- input := []byte(`{"arr":[1,2]}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "arr",
- "mode": "prepend",
- "value": 0,
- },
- map[string]interface{}{
- "path": "arr",
- "mode": "append",
- "value": []interface{}{3, 4},
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"arr":[0,1,2,3,4]}`, string(out))
- }
- func TestApplyParamOverrideAppendObjectMergeKeepOrigin(t *testing.T) {
- input := []byte(`{"obj":{"a":1}}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "obj",
- "mode": "append",
- "keep_origin": true,
- "value": map[string]interface{}{
- "a": 2,
- "b": 3,
- },
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"obj":{"a":1,"b":3}}`, string(out))
- }
- func TestApplyParamOverrideAppendObjectMergeOverride(t *testing.T) {
- input := []byte(`{"obj":{"a":1}}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "obj",
- "mode": "append",
- "value": map[string]interface{}{
- "a": 2,
- "b": 3,
- },
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"obj":{"a":2,"b":3}}`, string(out))
- }
- func TestApplyParamOverrideConditionORDefault(t *testing.T) {
- input := []byte(`{"model":"gpt-4","temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- "conditions": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "prefix",
- "value": "gpt",
- },
- map[string]interface{}{
- "path": "model",
- "mode": "prefix",
- "value": "claude",
- },
- },
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(out))
- }
- func TestApplyParamOverrideConditionAND(t *testing.T) {
- input := []byte(`{"model":"gpt-4","temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- "logic": "AND",
- "conditions": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "prefix",
- "value": "gpt",
- },
- map[string]interface{}{
- "path": "temperature",
- "mode": "gt",
- "value": 0.5,
- },
- },
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","temperature":0.1}`, string(out))
- }
- func TestApplyParamOverrideConditionInvert(t *testing.T) {
- input := []byte(`{"model":"gpt-4","temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- "conditions": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "prefix",
- "value": "gpt",
- "invert": true,
- },
- },
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","temperature":0.7}`, string(out))
- }
- func TestApplyParamOverrideConditionPassMissingKey(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- "conditions": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "prefix",
- "value": "gpt",
- "pass_missing_key": true,
- },
- },
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.1}`, string(out))
- }
- func TestApplyParamOverrideConditionFromContext(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- "conditions": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "prefix",
- "value": "gpt",
- },
- },
- },
- },
- }
- ctx := map[string]interface{}{
- "model": "gpt-4",
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.1}`, string(out))
- }
- func TestApplyParamOverrideNegativeIndexPath(t *testing.T) {
- input := []byte(`{"arr":[{"model":"a"},{"model":"b"}]}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "arr.-1.model",
- "mode": "set",
- "value": "c",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"arr":[{"model":"a"},{"model":"c"}]}`, string(out))
- }
- func TestApplyParamOverrideRegexReplaceInvalidPattern(t *testing.T) {
- // regex_replace invalid pattern example:
- // {"operations":[{"path":"model","mode":"regex_replace","from":"(","to":"x"}]}
- input := []byte(`{"model":"gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "regex_replace",
- "from": "(",
- "to": "x",
- },
- },
- }
- _, err := ApplyParamOverride(input, override, nil)
- if err == nil {
- t.Fatalf("expected error, got nil")
- }
- }
- func TestApplyParamOverrideCopy(t *testing.T) {
- // copy example:
- // {"operations":[{"mode":"copy","from":"model","to":"original_model"}]}
- input := []byte(`{"model":"gpt-4","temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "copy",
- "from": "model",
- "to": "original_model",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","original_model":"gpt-4","temperature":0.7}`, string(out))
- }
- func TestApplyParamOverrideCopyMissingSource(t *testing.T) {
- // copy missing source example:
- // {"operations":[{"mode":"copy","from":"model","to":"original_model"}]}
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "copy",
- "from": "model",
- "to": "original_model",
- },
- },
- }
- _, err := ApplyParamOverride(input, override, nil)
- if err == nil {
- t.Fatalf("expected error, got nil")
- }
- }
- func TestApplyParamOverrideCopyRequiresFromTo(t *testing.T) {
- // copy requires from/to example:
- // {"operations":[{"mode":"copy"}]}
- input := []byte(`{"model":"gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "copy",
- },
- },
- }
- _, err := ApplyParamOverride(input, override, nil)
- if err == nil {
- t.Fatalf("expected error, got nil")
- }
- }
- func TestApplyParamOverrideEnsurePrefix(t *testing.T) {
- // ensure_prefix example:
- // {"operations":[{"path":"model","mode":"ensure_prefix","value":"openai/"}]}
- input := []byte(`{"model":"gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "ensure_prefix",
- "value": "openai/",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"openai/gpt-4"}`, string(out))
- }
- func TestApplyParamOverrideEnsurePrefixNoop(t *testing.T) {
- // ensure_prefix no-op example:
- // {"operations":[{"path":"model","mode":"ensure_prefix","value":"openai/"}]}
- input := []byte(`{"model":"openai/gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "ensure_prefix",
- "value": "openai/",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"openai/gpt-4"}`, string(out))
- }
- func TestApplyParamOverrideEnsureSuffix(t *testing.T) {
- // ensure_suffix example:
- // {"operations":[{"path":"model","mode":"ensure_suffix","value":"-latest"}]}
- input := []byte(`{"model":"gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "ensure_suffix",
- "value": "-latest",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4-latest"}`, string(out))
- }
- func TestApplyParamOverrideEnsureSuffixNoop(t *testing.T) {
- // ensure_suffix no-op example:
- // {"operations":[{"path":"model","mode":"ensure_suffix","value":"-latest"}]}
- input := []byte(`{"model":"gpt-4-latest"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "ensure_suffix",
- "value": "-latest",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4-latest"}`, string(out))
- }
- func TestApplyParamOverrideEnsureRequiresValue(t *testing.T) {
- // ensure_prefix requires value example:
- // {"operations":[{"path":"model","mode":"ensure_prefix"}]}
- input := []byte(`{"model":"gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "ensure_prefix",
- },
- },
- }
- _, err := ApplyParamOverride(input, override, nil)
- if err == nil {
- t.Fatalf("expected error, got nil")
- }
- }
- func TestApplyParamOverrideTrimSpace(t *testing.T) {
- // trim_space example:
- // {"operations":[{"path":"model","mode":"trim_space"}]}
- input := []byte("{\"model\":\" gpt-4 \\n\"}")
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "trim_space",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4"}`, string(out))
- }
- func TestApplyParamOverrideToLower(t *testing.T) {
- // to_lower example:
- // {"operations":[{"path":"model","mode":"to_lower"}]}
- input := []byte(`{"model":"GPT-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "to_lower",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4"}`, string(out))
- }
- func TestApplyParamOverrideToUpper(t *testing.T) {
- // to_upper example:
- // {"operations":[{"path":"model","mode":"to_upper"}]}
- input := []byte(`{"model":"gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "model",
- "mode": "to_upper",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"GPT-4"}`, string(out))
- }
- func TestApplyParamOverrideReturnError(t *testing.T) {
- input := []byte(`{"model":"gemini-2.5-pro"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "return_error",
- "value": map[string]interface{}{
- "message": "forced bad request by param override",
- "status_code": 422,
- "code": "forced_bad_request",
- "type": "invalid_request_error",
- "skip_retry": true,
- },
- "conditions": []interface{}{
- map[string]interface{}{
- "path": "retry.is_retry",
- "mode": "full",
- "value": true,
- },
- },
- },
- },
- }
- ctx := map[string]interface{}{
- "retry": map[string]interface{}{
- "index": 1,
- "is_retry": true,
- },
- }
- _, err := ApplyParamOverride(input, override, ctx)
- if err == nil {
- t.Fatalf("expected error, got nil")
- }
- returnErr, ok := AsParamOverrideReturnError(err)
- if !ok {
- t.Fatalf("expected ParamOverrideReturnError, got %T: %v", err, err)
- }
- if returnErr.StatusCode != 422 {
- t.Fatalf("expected status 422, got %d", returnErr.StatusCode)
- }
- if returnErr.Code != "forced_bad_request" {
- t.Fatalf("expected code forced_bad_request, got %s", returnErr.Code)
- }
- if !returnErr.SkipRetry {
- t.Fatalf("expected skip_retry true")
- }
- }
- func TestApplyParamOverridePruneObjectsByTypeString(t *testing.T) {
- input := []byte(`{
- "messages":[
- {"role":"assistant","content":[
- {"type":"output_text","text":"a"},
- {"type":"redacted_thinking","text":"secret"},
- {"type":"tool_call","name":"tool_a"}
- ]},
- {"role":"assistant","content":[
- {"type":"output_text","text":"b"},
- {"type":"wrapper","parts":[
- {"type":"redacted_thinking","text":"secret2"},
- {"type":"output_text","text":"c"}
- ]}
- ]}
- ]
- }`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "prune_objects",
- "value": "redacted_thinking",
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{
- "messages":[
- {"role":"assistant","content":[
- {"type":"output_text","text":"a"},
- {"type":"tool_call","name":"tool_a"}
- ]},
- {"role":"assistant","content":[
- {"type":"output_text","text":"b"},
- {"type":"wrapper","parts":[
- {"type":"output_text","text":"c"}
- ]}
- ]}
- ]
- }`, string(out))
- }
- func TestApplyParamOverridePruneObjectsWhereAndPath(t *testing.T) {
- input := []byte(`{
- "a":{"items":[{"type":"redacted_thinking","id":1},{"type":"output_text","id":2}]},
- "b":{"items":[{"type":"redacted_thinking","id":3},{"type":"output_text","id":4}]}
- }`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "a",
- "mode": "prune_objects",
- "value": map[string]interface{}{
- "where": map[string]interface{}{
- "type": "redacted_thinking",
- },
- },
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{
- "a":{"items":[{"type":"output_text","id":2}]},
- "b":{"items":[{"type":"redacted_thinking","id":3},{"type":"output_text","id":4}]}
- }`, string(out))
- }
- func TestApplyParamOverrideNormalizeThinkingSignatureUnsupported(t *testing.T) {
- input := []byte(`{"items":[{"type":"redacted_thinking"}]}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "normalize_thinking_signature",
- },
- },
- }
- _, err := ApplyParamOverride(input, override, nil)
- if err == nil {
- t.Fatalf("expected error, got nil")
- }
- }
- func TestApplyParamOverrideConditionFromRetryAndLastErrorContext(t *testing.T) {
- info := &RelayInfo{
- RetryIndex: 1,
- LastError: types.WithOpenAIError(types.OpenAIError{
- Message: "invalid thinking signature",
- Type: "invalid_request_error",
- Code: "bad_thought_signature",
- }, 400),
- }
- ctx := BuildParamOverrideContext(info)
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- "logic": "AND",
- "conditions": []interface{}{
- map[string]interface{}{
- "path": "is_retry",
- "mode": "full",
- "value": true,
- },
- map[string]interface{}{
- "path": "last_error.code",
- "mode": "contains",
- "value": "thought_signature",
- },
- },
- },
- },
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.1}`, string(out))
- }
- func TestApplyParamOverrideConditionFromRequestHeaders(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- "conditions": []interface{}{
- map[string]interface{}{
- "path": "request_headers.authorization",
- "mode": "contains",
- "value": "Bearer ",
- },
- },
- },
- },
- }
- ctx := map[string]interface{}{
- "request_headers": map[string]interface{}{
- "authorization": "Bearer token-123",
- },
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.1}`, string(out))
- }
- func TestApplyParamOverrideSetHeaderAndUseInLaterCondition(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "set_header",
- "path": "X-Debug-Mode",
- "value": "enabled",
- },
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- "conditions": []interface{}{
- map[string]interface{}{
- "path": "header_override.x-debug-mode",
- "mode": "full",
- "value": "enabled",
- },
- },
- },
- },
- }
- out, err := ApplyParamOverride(input, override, nil)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.1}`, string(out))
- }
- func TestApplyParamOverrideCopyHeaderFromRequestHeaders(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "copy_header",
- "from": "Authorization",
- "to": "X-Upstream-Auth",
- },
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- "conditions": []interface{}{
- map[string]interface{}{
- "path": "header_override.x-upstream-auth",
- "mode": "contains",
- "value": "Bearer ",
- },
- },
- },
- },
- }
- ctx := map[string]interface{}{
- "request_headers": map[string]interface{}{
- "authorization": "Bearer token-123",
- },
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.1}`, string(out))
- }
- func TestApplyParamOverridePassHeadersSkipsMissingHeaders(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "pass_headers",
- "value": []interface{}{"X-Codex-Beta-Features", "Session_id"},
- },
- },
- }
- ctx := map[string]interface{}{
- "request_headers": map[string]interface{}{
- "session_id": "sess-123",
- },
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.7}`, string(out))
- headers, ok := ctx["header_override"].(map[string]interface{})
- if !ok {
- t.Fatalf("expected header_override context map")
- }
- if headers["session_id"] != "sess-123" {
- t.Fatalf("expected session_id to be passed, got: %v", headers["session_id"])
- }
- if _, exists := headers["x-codex-beta-features"]; exists {
- t.Fatalf("expected missing header to be skipped")
- }
- }
- func TestApplyParamOverrideCopyHeaderSkipsMissingSource(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "copy_header",
- "from": "X-Missing-Header",
- "to": "X-Upstream-Auth",
- },
- },
- }
- ctx := map[string]interface{}{
- "request_headers": map[string]interface{}{
- "authorization": "Bearer token-123",
- },
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.7}`, string(out))
- headers, ok := ctx["header_override"].(map[string]interface{})
- if !ok {
- return
- }
- if _, exists := headers["x-upstream-auth"]; exists {
- t.Fatalf("expected X-Upstream-Auth to be skipped when source header is missing")
- }
- }
- func TestApplyParamOverrideMoveHeaderSkipsMissingSource(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "move_header",
- "from": "X-Missing-Header",
- "to": "X-Upstream-Auth",
- },
- },
- }
- ctx := map[string]interface{}{
- "request_headers": map[string]interface{}{
- "authorization": "Bearer token-123",
- },
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.7}`, string(out))
- headers, ok := ctx["header_override"].(map[string]interface{})
- if !ok {
- return
- }
- if _, exists := headers["x-upstream-auth"]; exists {
- t.Fatalf("expected X-Upstream-Auth to be skipped when source header is missing")
- }
- }
- func TestApplyParamOverrideSyncFieldsHeaderToJSON(t *testing.T) {
- input := []byte(`{"model":"gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "sync_fields",
- "from": "header:session_id",
- "to": "json:prompt_cache_key",
- },
- },
- }
- ctx := map[string]interface{}{
- "request_headers": map[string]interface{}{
- "session_id": "sess-123",
- },
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","prompt_cache_key":"sess-123"}`, string(out))
- }
- func TestApplyParamOverrideSyncFieldsJSONToHeader(t *testing.T) {
- input := []byte(`{"model":"gpt-4","prompt_cache_key":"cache-abc"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "sync_fields",
- "from": "header:session_id",
- "to": "json:prompt_cache_key",
- },
- },
- }
- ctx := map[string]interface{}{}
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","prompt_cache_key":"cache-abc"}`, string(out))
- headers, ok := ctx["header_override"].(map[string]interface{})
- if !ok {
- t.Fatalf("expected header_override context map")
- }
- if headers["session_id"] != "cache-abc" {
- t.Fatalf("expected session_id to be synced from prompt_cache_key, got: %v", headers["session_id"])
- }
- }
- func TestApplyParamOverrideSyncFieldsNoChangeWhenBothExist(t *testing.T) {
- input := []byte(`{"model":"gpt-4","prompt_cache_key":"cache-body"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "sync_fields",
- "from": "header:session_id",
- "to": "json:prompt_cache_key",
- },
- },
- }
- ctx := map[string]interface{}{
- "request_headers": map[string]interface{}{
- "session_id": "cache-header",
- },
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-4","prompt_cache_key":"cache-body"}`, string(out))
- headers, _ := ctx["header_override"].(map[string]interface{})
- if headers != nil {
- if _, exists := headers["session_id"]; exists {
- t.Fatalf("expected no override when both sides already have value")
- }
- }
- }
- func TestApplyParamOverrideSyncFieldsInvalidTarget(t *testing.T) {
- input := []byte(`{"model":"gpt-4"}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "sync_fields",
- "from": "foo:session_id",
- "to": "json:prompt_cache_key",
- },
- },
- }
- _, err := ApplyParamOverride(input, override, nil)
- if err == nil {
- t.Fatalf("expected error, got nil")
- }
- }
- func TestApplyParamOverrideSetHeaderKeepOrigin(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "set_header",
- "path": "X-Feature-Flag",
- "value": "new-value",
- "keep_origin": true,
- },
- },
- }
- ctx := map[string]interface{}{
- "header_override": map[string]interface{}{
- "x-feature-flag": "legacy-value",
- },
- }
- _, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- headers, ok := ctx["header_override"].(map[string]interface{})
- if !ok {
- t.Fatalf("expected header_override context map")
- }
- if headers["x-feature-flag"] != "legacy-value" {
- t.Fatalf("expected keep_origin to preserve old value, got: %v", headers["x-feature-flag"])
- }
- }
- func TestApplyParamOverrideSetHeaderMapRewritesCommaSeparatedHeader(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "set_header",
- "path": "anthropic-beta",
- "value": map[string]interface{}{
- "advanced-tool-use-2025-11-20": nil,
- "computer-use-2025-01-24": "computer-use-2025-01-24",
- },
- },
- },
- }
- ctx := map[string]interface{}{
- "request_headers": map[string]interface{}{
- "anthropic-beta": "advanced-tool-use-2025-11-20, computer-use-2025-01-24",
- },
- }
- _, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- headers, ok := ctx["header_override"].(map[string]interface{})
- if !ok {
- t.Fatalf("expected header_override context map")
- }
- if headers["anthropic-beta"] != "computer-use-2025-01-24" {
- t.Fatalf("expected anthropic-beta to keep only mapped value, got: %v", headers["anthropic-beta"])
- }
- }
- func TestApplyParamOverrideSetHeaderMapDeleteWholeHeaderWhenAllTokensCleared(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "set_header",
- "path": "anthropic-beta",
- "value": map[string]interface{}{
- "advanced-tool-use-2025-11-20": nil,
- "computer-use-2025-01-24": nil,
- },
- },
- },
- }
- ctx := map[string]interface{}{
- "header_override": map[string]interface{}{
- "anthropic-beta": "advanced-tool-use-2025-11-20,computer-use-2025-01-24",
- },
- }
- _, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- headers, ok := ctx["header_override"].(map[string]interface{})
- if !ok {
- t.Fatalf("expected header_override context map")
- }
- if _, exists := headers["anthropic-beta"]; exists {
- t.Fatalf("expected anthropic-beta to be deleted when all mapped values are null")
- }
- }
- func TestApplyParamOverrideSetHeaderMapAppendsTokens(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "set_header",
- "path": "anthropic-beta",
- "value": map[string]interface{}{
- "$append": []interface{}{"context-1m-2025-08-07", "computer-use-2025-01-24"},
- },
- },
- },
- }
- ctx := map[string]interface{}{
- "header_override": map[string]interface{}{
- "anthropic-beta": "computer-use-2025-01-24",
- },
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.7}`, string(out))
- headers, ok := ctx["header_override"].(map[string]interface{})
- if !ok {
- t.Fatalf("expected header_override context map")
- }
- if headers["anthropic-beta"] != "computer-use-2025-01-24,context-1m-2025-08-07" {
- t.Fatalf("expected anthropic-beta to append new token without duplicates, got: %v", headers["anthropic-beta"])
- }
- }
- func TestApplyParamOverrideSetHeaderMapAppendsTokensWhenHeaderMissing(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "set_header",
- "path": "anthropic-beta",
- "value": map[string]interface{}{
- "$append": []interface{}{"context-1m-2025-08-07", "computer-use-2025-01-24"},
- },
- },
- },
- }
- ctx := map[string]interface{}{}
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.7}`, string(out))
- headers, ok := ctx["header_override"].(map[string]interface{})
- if !ok {
- t.Fatalf("expected header_override context map")
- }
- if headers["anthropic-beta"] != "context-1m-2025-08-07,computer-use-2025-01-24" {
- t.Fatalf("expected anthropic-beta to be created from appended tokens, got: %v", headers["anthropic-beta"])
- }
- }
- func TestApplyParamOverrideSetHeaderMapKeepOnlyDeclaredDropsUndeclaredTokens(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "set_header",
- "path": "anthropic-beta",
- "value": map[string]interface{}{
- "computer-use-2025-01-24": "computer-use-2025-01-24",
- "$append": []interface{}{"context-1m-2025-08-07"},
- "$keep_only_declared": true,
- },
- },
- },
- }
- ctx := map[string]interface{}{
- "header_override": map[string]interface{}{
- "anthropic-beta": "advanced-tool-use-2025-11-20,computer-use-2025-01-24",
- },
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.7}`, string(out))
- headers, ok := ctx["header_override"].(map[string]interface{})
- if !ok {
- t.Fatalf("expected header_override context map")
- }
- if headers["anthropic-beta"] != "computer-use-2025-01-24,context-1m-2025-08-07" {
- t.Fatalf("expected anthropic-beta to keep only declared tokens, got: %v", headers["anthropic-beta"])
- }
- }
- func TestApplyParamOverrideSetHeaderMapKeepOnlyDeclaredDeletesHeaderWhenNothingDeclaredMatches(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "set_header",
- "path": "anthropic-beta",
- "value": map[string]interface{}{
- "computer-use-2025-01-24": "computer-use-2025-01-24",
- "$keep_only_declared": true,
- },
- },
- },
- }
- ctx := map[string]interface{}{
- "header_override": map[string]interface{}{
- "anthropic-beta": "advanced-tool-use-2025-11-20",
- },
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.7}`, string(out))
- headers, ok := ctx["header_override"].(map[string]interface{})
- if !ok {
- t.Fatalf("expected header_override context map")
- }
- if _, exists := headers["anthropic-beta"]; exists {
- t.Fatalf("expected anthropic-beta to be deleted when no declared tokens remain, got: %v", headers["anthropic-beta"])
- }
- }
- func TestApplyParamOverrideConditionsObjectShorthand(t *testing.T) {
- input := []byte(`{"temperature":0.7}`)
- override := map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "path": "temperature",
- "mode": "set",
- "value": 0.1,
- "logic": "AND",
- "conditions": map[string]interface{}{
- "is_retry": true,
- "last_error.status_code": 400.0,
- },
- },
- },
- }
- ctx := map[string]interface{}{
- "is_retry": true,
- "last_error": map[string]interface{}{
- "status_code": 400.0,
- },
- }
- out, err := ApplyParamOverride(input, override, ctx)
- if err != nil {
- t.Fatalf("ApplyParamOverride returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.1}`, string(out))
- }
- func TestApplyParamOverrideWithRelayInfoSyncRuntimeHeaders(t *testing.T) {
- info := &RelayInfo{
- ChannelMeta: &ChannelMeta{
- ParamOverride: map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "set_header",
- "path": "X-Injected-By-Param-Override",
- "value": "enabled",
- },
- map[string]interface{}{
- "mode": "delete_header",
- "path": "X-Delete-Me",
- },
- },
- },
- HeadersOverride: map[string]interface{}{
- "X-Delete-Me": "legacy",
- "X-Keep-Me": "keep",
- },
- },
- }
- input := []byte(`{"temperature":0.7}`)
- out, err := ApplyParamOverrideWithRelayInfo(input, info)
- if err != nil {
- t.Fatalf("ApplyParamOverrideWithRelayInfo returned error: %v", err)
- }
- assertJSONEqual(t, `{"temperature":0.7}`, string(out))
- if !info.UseRuntimeHeadersOverride {
- t.Fatalf("expected runtime header override to be enabled")
- }
- if info.RuntimeHeadersOverride["x-keep-me"] != "keep" {
- t.Fatalf("expected x-keep-me header to be preserved, got: %v", info.RuntimeHeadersOverride["x-keep-me"])
- }
- if info.RuntimeHeadersOverride["x-injected-by-param-override"] != "enabled" {
- t.Fatalf("expected x-injected-by-param-override header to be set, got: %v", info.RuntimeHeadersOverride["x-injected-by-param-override"])
- }
- if _, exists := info.RuntimeHeadersOverride["x-delete-me"]; exists {
- t.Fatalf("expected x-delete-me header to be deleted")
- }
- }
- func TestApplyParamOverrideWithRelayInfoMixedLegacyAndOperations(t *testing.T) {
- info := &RelayInfo{
- RequestHeaders: map[string]string{
- "Originator": "Codex CLI",
- },
- ChannelMeta: &ChannelMeta{
- ParamOverride: map[string]interface{}{
- "temperature": 0.2,
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "pass_headers",
- "value": []interface{}{"Originator"},
- },
- },
- },
- HeadersOverride: map[string]interface{}{
- "X-Static": "legacy-static",
- },
- },
- }
- out, err := ApplyParamOverrideWithRelayInfo([]byte(`{"model":"gpt-5","temperature":0.7}`), info)
- if err != nil {
- t.Fatalf("ApplyParamOverrideWithRelayInfo returned error: %v", err)
- }
- assertJSONEqual(t, `{"model":"gpt-5","temperature":0.2}`, string(out))
- if !info.UseRuntimeHeadersOverride {
- t.Fatalf("expected runtime header override to be enabled")
- }
- if info.RuntimeHeadersOverride["x-static"] != "legacy-static" {
- t.Fatalf("expected x-static to be preserved, got: %v", info.RuntimeHeadersOverride["x-static"])
- }
- if info.RuntimeHeadersOverride["originator"] != "Codex CLI" {
- t.Fatalf("expected originator header to be passed, got: %v", info.RuntimeHeadersOverride["originator"])
- }
- }
- func TestApplyParamOverrideWithRelayInfoMoveAndCopyHeaders(t *testing.T) {
- info := &RelayInfo{
- ChannelMeta: &ChannelMeta{
- ParamOverride: map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "move_header",
- "from": "X-Legacy-Trace",
- "to": "X-Trace",
- },
- map[string]interface{}{
- "mode": "copy_header",
- "from": "X-Trace",
- "to": "X-Trace-Backup",
- },
- },
- },
- HeadersOverride: map[string]interface{}{
- "X-Legacy-Trace": "trace-123",
- },
- },
- }
- input := []byte(`{"temperature":0.7}`)
- _, err := ApplyParamOverrideWithRelayInfo(input, info)
- if err != nil {
- t.Fatalf("ApplyParamOverrideWithRelayInfo returned error: %v", err)
- }
- if _, exists := info.RuntimeHeadersOverride["x-legacy-trace"]; exists {
- t.Fatalf("expected source header to be removed after move")
- }
- if info.RuntimeHeadersOverride["x-trace"] != "trace-123" {
- t.Fatalf("expected x-trace to be set, got: %v", info.RuntimeHeadersOverride["x-trace"])
- }
- if info.RuntimeHeadersOverride["x-trace-backup"] != "trace-123" {
- t.Fatalf("expected x-trace-backup to be copied, got: %v", info.RuntimeHeadersOverride["x-trace-backup"])
- }
- }
- func TestApplyParamOverrideWithRelayInfoSetHeaderMapRewritesAnthropicBeta(t *testing.T) {
- info := &RelayInfo{
- ChannelMeta: &ChannelMeta{
- ParamOverride: map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "set_header",
- "path": "anthropic-beta",
- "value": map[string]interface{}{
- "advanced-tool-use-2025-11-20": nil,
- "computer-use-2025-01-24": "computer-use-2025-01-24",
- },
- },
- },
- },
- HeadersOverride: map[string]interface{}{
- "anthropic-beta": "advanced-tool-use-2025-11-20, computer-use-2025-01-24",
- },
- },
- }
- _, err := ApplyParamOverrideWithRelayInfo([]byte(`{"temperature":0.7}`), info)
- if err != nil {
- t.Fatalf("ApplyParamOverrideWithRelayInfo returned error: %v", err)
- }
- if !info.UseRuntimeHeadersOverride {
- t.Fatalf("expected runtime header override to be enabled")
- }
- if info.RuntimeHeadersOverride["anthropic-beta"] != "computer-use-2025-01-24" {
- t.Fatalf("expected anthropic-beta to be rewritten, got: %v", info.RuntimeHeadersOverride["anthropic-beta"])
- }
- }
- func TestGetEffectiveHeaderOverrideUsesRuntimeOverrideAsFinalResult(t *testing.T) {
- info := &RelayInfo{
- UseRuntimeHeadersOverride: true,
- RuntimeHeadersOverride: map[string]interface{}{
- "x-runtime": "runtime-only",
- },
- ChannelMeta: &ChannelMeta{
- HeadersOverride: map[string]interface{}{
- "X-Static": "static-value",
- "X-Deleted": "should-not-exist",
- },
- },
- }
- effective := GetEffectiveHeaderOverride(info)
- if effective["x-runtime"] != "runtime-only" {
- t.Fatalf("expected x-runtime from runtime override, got: %v", effective["x-runtime"])
- }
- if _, exists := effective["x-static"]; exists {
- t.Fatalf("expected runtime override to be final and not merge channel headers")
- }
- }
- func TestRemoveDisabledFieldsSkipWhenChannelPassThroughEnabled(t *testing.T) {
- input := `{
- "service_tier":"flex",
- "safety_identifier":"user-123",
- "store":true,
- "stream_options":{"include_obfuscation":false}
- }`
- settings := dto.ChannelOtherSettings{}
- out, err := RemoveDisabledFields([]byte(input), settings, true)
- if err != nil {
- t.Fatalf("RemoveDisabledFields returned error: %v", err)
- }
- assertJSONEqual(t, input, string(out))
- }
- func TestRemoveDisabledFieldsSkipWhenGlobalPassThroughEnabled(t *testing.T) {
- original := model_setting.GetGlobalSettings().PassThroughRequestEnabled
- model_setting.GetGlobalSettings().PassThroughRequestEnabled = true
- t.Cleanup(func() {
- model_setting.GetGlobalSettings().PassThroughRequestEnabled = original
- })
- input := `{
- "service_tier":"flex",
- "safety_identifier":"user-123",
- "stream_options":{"include_obfuscation":false}
- }`
- settings := dto.ChannelOtherSettings{}
- out, err := RemoveDisabledFields([]byte(input), settings, false)
- if err != nil {
- t.Fatalf("RemoveDisabledFields returned error: %v", err)
- }
- assertJSONEqual(t, input, string(out))
- }
- func TestRemoveDisabledFieldsDefaultFiltering(t *testing.T) {
- input := `{
- "service_tier":"flex",
- "inference_geo":"eu",
- "speed":"fast",
- "cache_control":{"type":"ephemeral"},
- "safety_identifier":"user-123",
- "store":true,
- "stream_options":{"include_obfuscation":false}
- }`
- settings := dto.ChannelOtherSettings{}
- out, err := RemoveDisabledFields([]byte(input), settings, false)
- if err != nil {
- t.Fatalf("RemoveDisabledFields returned error: %v", err)
- }
- assertJSONEqual(t, `{"cache_control":{"type":"ephemeral"},"store":true}`, string(out))
- }
- func TestRemoveDisabledFieldsAllowInferenceGeo(t *testing.T) {
- input := `{
- "inference_geo":"eu",
- "store":true
- }`
- settings := dto.ChannelOtherSettings{
- AllowInferenceGeo: true,
- }
- out, err := RemoveDisabledFields([]byte(input), settings, false)
- if err != nil {
- t.Fatalf("RemoveDisabledFields returned error: %v", err)
- }
- assertJSONEqual(t, `{"inference_geo":"eu","store":true}`, string(out))
- }
- func TestRemoveDisabledFieldsAllowSpeed(t *testing.T) {
- input := `{
- "speed":"fast",
- "store":true
- }`
- settings := dto.ChannelOtherSettings{
- AllowSpeed: true,
- }
- out, err := RemoveDisabledFields([]byte(input), settings, false)
- if err != nil {
- t.Fatalf("RemoveDisabledFields returned error: %v", err)
- }
- assertJSONEqual(t, `{"speed":"fast","store":true}`, string(out))
- }
- func TestApplyParamOverrideWithRelayInfoRecordsOperationAuditInDebugMode(t *testing.T) {
- originalDebugEnabled := common2.DebugEnabled
- common2.DebugEnabled = true
- t.Cleanup(func() {
- common2.DebugEnabled = originalDebugEnabled
- })
- info := &RelayInfo{
- ChannelMeta: &ChannelMeta{
- ParamOverride: map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "copy",
- "from": "metadata.target_model",
- "to": "model",
- },
- map[string]interface{}{
- "mode": "set",
- "path": "service_tier",
- "value": "flex",
- },
- map[string]interface{}{
- "mode": "set",
- "path": "temperature",
- "value": 0.1,
- },
- },
- },
- },
- }
- out, err := ApplyParamOverrideWithRelayInfo([]byte(`{
- "model":"gpt-4.1",
- "temperature":0.7,
- "metadata":{"target_model":"gpt-4.1-mini"}
- }`), info)
- if err != nil {
- t.Fatalf("ApplyParamOverrideWithRelayInfo returned error: %v", err)
- }
- assertJSONEqual(t, `{
- "model":"gpt-4.1-mini",
- "temperature":0.1,
- "service_tier":"flex",
- "metadata":{"target_model":"gpt-4.1-mini"}
- }`, string(out))
- expected := []string{
- "copy metadata.target_model -> model",
- "set service_tier = flex",
- "set temperature = 0.1",
- }
- if !reflect.DeepEqual(info.ParamOverrideAudit, expected) {
- t.Fatalf("unexpected param override audit, got %#v", info.ParamOverrideAudit)
- }
- }
- func TestApplyParamOverrideWithRelayInfoRecordsOnlyKeyOperationsWhenDebugDisabled(t *testing.T) {
- originalDebugEnabled := common2.DebugEnabled
- common2.DebugEnabled = false
- t.Cleanup(func() {
- common2.DebugEnabled = originalDebugEnabled
- })
- info := &RelayInfo{
- ChannelMeta: &ChannelMeta{
- ParamOverride: map[string]interface{}{
- "operations": []interface{}{
- map[string]interface{}{
- "mode": "copy",
- "from": "metadata.target_model",
- "to": "model",
- },
- map[string]interface{}{
- "mode": "set",
- "path": "temperature",
- "value": 0.1,
- },
- },
- },
- },
- }
- _, err := ApplyParamOverrideWithRelayInfo([]byte(`{
- "model":"gpt-4.1",
- "temperature":0.7,
- "metadata":{"target_model":"gpt-4.1-mini"}
- }`), info)
- if err != nil {
- t.Fatalf("ApplyParamOverrideWithRelayInfo returned error: %v", err)
- }
- expected := []string{
- "copy metadata.target_model -> model",
- }
- if !reflect.DeepEqual(info.ParamOverrideAudit, expected) {
- t.Fatalf("unexpected param override audit, got %#v", info.ParamOverrideAudit)
- }
- }
- func assertJSONEqual(t *testing.T, want, got string) {
- t.Helper()
- var wantObj interface{}
- var gotObj interface{}
- if err := json.Unmarshal([]byte(want), &wantObj); err != nil {
- t.Fatalf("failed to unmarshal want JSON: %v", err)
- }
- if err := json.Unmarshal([]byte(got), &gotObj); err != nil {
- t.Fatalf("failed to unmarshal got JSON: %v", err)
- }
- if !reflect.DeepEqual(wantObj, gotObj) {
- t.Fatalf("json not equal\nwant: %s\ngot: %s", want, got)
- }
- }
|