From a4b6f04efd1f44e76b7cf6dbd70b2a974ab4de47 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 31 Mar 2026 20:24:36 +0000 Subject: [PATCH 1/3] feat: add WSDL support to scaffold command Extend the scaffold command to discover WSDL files and generate soap plugin configurations. Uses go-wsdl-parser to parse WSDL operations and create appropriate mock resources. Closes #90 https://claude.ai/code/session_01Xsiik4SZGtBrKQi7LxKtXZ --- cmd/scaffold.go | 5 +- cmd/scaffold_test.go | 40 ++++++++++++++ cmd/testdata/pet_service.wsdl | 61 +++++++++++++++++++++ go.mod | 20 +++++-- go.sum | 80 ++++++++++++++++++++++++++++ internal/impostermodel/configfile.go | 40 ++++++++++---- internal/impostermodel/model.go | 4 +- internal/impostermodel/wsdl.go | 46 ++++++++++++++++ internal/wsdl/discovery.go | 20 +++++++ 9 files changed, 299 insertions(+), 17 deletions(-) create mode 100644 cmd/testdata/pet_service.wsdl create mode 100644 internal/impostermodel/wsdl.go create mode 100644 internal/wsdl/discovery.go diff --git a/cmd/scaffold.go b/cmd/scaffold.go index 242ff8c..eb2a6e9 100644 --- a/cmd/scaffold.go +++ b/cmd/scaffold.go @@ -35,8 +35,9 @@ var scaffoldCmd = &cobra.Command{ Aliases: []string{"init"}, Short: "Create Imposter configuration", Long: `Creates Imposter configuration files. If one or more OpenAPI/Swagger -specification files are present, they are used as the basis for the generated -resources. If no specification files are present, a simple REST mock is created. +specification files or WSDL files are present, they are used as the basis for +the generated resources. If no specification files are present, a simple REST +mock is created. If DIR is not specified, the current working directory is used.`, Args: cobra.RangeArgs(0, 1), diff --git a/cmd/scaffold_test.go b/cmd/scaffold_test.go index 818186d..c02606f 100644 --- a/cmd/scaffold_test.go +++ b/cmd/scaffold_test.go @@ -41,6 +41,7 @@ func Test_createMockConfig(t *testing.T) { forceOverwrite bool scriptEngine impostermodel2.ScriptEngine copySpecs bool + copyWsdl bool anchorFileName string checkResponseFile bool } @@ -114,6 +115,39 @@ func Test_createMockConfig(t *testing.T) { checkResponseFile: true, }, }, + { + name: "generate wsdl mock with resources no script", + args: args{ + generateResources: true, + forceOverwrite: true, + scriptEngine: impostermodel2.ScriptEngineNone, + anchorFileName: "pet_service", + copyWsdl: true, + checkResponseFile: false, + }, + }, + { + name: "generate wsdl mock with resources with script", + args: args{ + generateResources: true, + forceOverwrite: true, + scriptEngine: impostermodel2.ScriptEngineJavaScript, + anchorFileName: "pet_service", + copyWsdl: true, + checkResponseFile: false, + }, + }, + { + name: "generate wsdl mock no resources no script", + args: args{ + generateResources: false, + forceOverwrite: true, + scriptEngine: impostermodel2.ScriptEngineNone, + anchorFileName: "pet_service", + copyWsdl: true, + checkResponseFile: false, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -124,6 +158,12 @@ func Test_createMockConfig(t *testing.T) { if tt.args.copySpecs { prepTestData(t, configDir, testConfigPath) } + if tt.args.copyWsdl { + err = fileutil.CopyFile(filepath.Join(testConfigPath, "pet_service.wsdl"), filepath.Join(configDir, "pet_service.wsdl")) + if err != nil { + t.Fatal(err) + } + } impostermodel2.Create(configDir, tt.args.generateResources, tt.args.forceOverwrite, tt.args.scriptEngine, false) if !doesFileExist(filepath.Join(configDir, tt.args.anchorFileName+"-config.yaml")) { diff --git a/cmd/testdata/pet_service.wsdl b/cmd/testdata/pet_service.wsdl new file mode 100644 index 0000000..9ef5bb0 --- /dev/null +++ b/cmd/testdata/pet_service.wsdl @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/go.mod b/go.mod index 79ccb13..e814987 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,13 @@ require ( sigs.k8s.io/yaml v1.6.0 ) +require ( + github.com/antchfx/xmlquery v1.4.4 // indirect + github.com/antchfx/xpath v1.3.4 // indirect + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect + golang.org/x/net v0.42.0 // indirect +) + require ( github.com/Microsoft/go-winio v0.6.1 // indirect github.com/containerd/errdefs v1.0.0 // indirect @@ -52,6 +59,7 @@ require ( github.com/olekukonko/ll v0.0.9 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/outofcoffee/go-wsdl-parser v0.0.0 github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect @@ -78,12 +86,14 @@ require ( go.uber.org/multierr v1.9.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/mod v0.22.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/text v0.28.0 // indirect + golang.org/x/tools v0.35.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect ) + +replace github.com/outofcoffee/go-wsdl-parser => /home/user/go-wsdl-parser diff --git a/go.sum b/go.sum index 3f32ac8..2e8d6bd 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,11 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/antchfx/xmlquery v1.4.4 h1:mxMEkdYP3pjKSftxss4nUHfjBhnMk4imGoR96FRY2dg= +github.com/antchfx/xmlquery v1.4.4/go.mod h1:AEPEEPYE9GnA2mj5Ur2L5Q5/2PycJ0N9Fusrx9b12fc= +github.com/antchfx/xpath v1.3.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= +github.com/antchfx/xpath v1.3.4 h1:1ixrW1VnXd4HurCj7qnqnR0jo14g8JMe20Fshg1Vgz4= +github.com/antchfx/xpath v1.3.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA= github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw= github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ= @@ -46,7 +51,11 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -155,6 +164,7 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= @@ -183,29 +193,99 @@ go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0= diff --git a/internal/impostermodel/configfile.go b/internal/impostermodel/configfile.go index 2eef849..360c8f8 100644 --- a/internal/impostermodel/configfile.go +++ b/internal/impostermodel/configfile.go @@ -20,6 +20,7 @@ import ( "gatehill.io/imposter/internal/fileutil" "gatehill.io/imposter/internal/logging" "gatehill.io/imposter/internal/openapi" + "gatehill.io/imposter/internal/wsdl" "os" "path" "path/filepath" @@ -31,28 +32,46 @@ type ConfigGenerationOptions struct { ScriptEngine ScriptEngine ScriptFileName string SpecFilePath string + WSDLFilePath string } var logger = logging.GetLogger() func Create(configDir string, generateResources bool, forceOverwrite bool, scriptEngine ScriptEngine, requireOpenApi bool) { openApiSpecs := openapi.DiscoverOpenApiSpecs(configDir) - logger.Infof("found %d OpenAPI spec(s)", len(openApiSpecs)) + wsdlFiles := wsdl.DiscoverWSDLFiles(configDir) + logger.Infof("found %d OpenAPI spec(s) and %d WSDL file(s)", len(openApiSpecs), len(wsdlFiles)) + + specsFound := false if len(openApiSpecs) > 0 { + specsFound = true logger.Tracef("using openapi plugin") for _, openApiSpec := range openApiSpecs { scriptFileName := getScriptFileName(openApiSpec, scriptEngine, forceOverwrite) writeOpenapiMockConfig(openApiSpec, generateResources, forceOverwrite, scriptEngine, scriptFileName) } - } else if !requireOpenApi { - logger.Infof("falling back to rest plugin") - syntheticMockPath := path.Join(configDir, "mock.txt") - _, responseFilePath := generateRestMockFiles(configDir) - scriptFileName := getScriptFileName(syntheticMockPath, scriptEngine, forceOverwrite) - writeRestMockConfig(syntheticMockPath, responseFilePath, generateResources, forceOverwrite, scriptEngine, scriptFileName) - } else { - logger.Fatalf("no OpenAPI specs found in: %s", configDir) + } + + if len(wsdlFiles) > 0 { + specsFound = true + logger.Tracef("using soap plugin") + for _, wsdlFile := range wsdlFiles { + scriptFileName := getScriptFileName(wsdlFile, scriptEngine, forceOverwrite) + writeWsdlMockConfig(wsdlFile, generateResources, forceOverwrite, scriptEngine, scriptFileName) + } + } + + if !specsFound { + if !requireOpenApi { + logger.Infof("falling back to rest plugin") + syntheticMockPath := path.Join(configDir, "mock.txt") + _, responseFilePath := generateRestMockFiles(configDir) + scriptFileName := getScriptFileName(syntheticMockPath, scriptEngine, forceOverwrite) + writeRestMockConfig(syntheticMockPath, responseFilePath, generateResources, forceOverwrite, scriptEngine, scriptFileName) + } else { + logger.Fatalf("no OpenAPI or WSDL specs found in: %s", configDir) + } } } @@ -63,6 +82,9 @@ func GenerateConfig(options ConfigGenerationOptions, resources []Resource) []byt if options.SpecFilePath != "" { pluginConfig.SpecFile = filepath.Base(options.SpecFilePath) } + if options.WSDLFilePath != "" { + pluginConfig.WSDLFile = filepath.Base(options.WSDLFilePath) + } if len(resources) > 0 { pluginConfig.Resources = resources } else { diff --git a/internal/impostermodel/model.go b/internal/impostermodel/model.go index 4ec6909..3edc344 100644 --- a/internal/impostermodel/model.go +++ b/internal/impostermodel/model.go @@ -31,8 +31,9 @@ type RequestBody struct { } type Resource struct { - Path string `json:"path"` + Path string `json:"path,omitempty"` Method string `json:"method"` + Operation string `json:"operation,omitempty"` QueryParams *map[string]string `json:"queryParams,omitempty"` RequestBody *RequestBody `json:"requestBody,omitempty"` RequestHeaders *map[string]string `json:"requestHeaders,omitempty"` @@ -42,6 +43,7 @@ type Resource struct { type PluginConfig struct { Plugin string `json:"plugin"` SpecFile string `json:"specFile,omitempty"` + WSDLFile string `json:"wsdlFile,omitempty"` Response *ResponseConfig `json:"response,omitempty"` Resources []Resource `json:"resources,omitempty"` } diff --git a/internal/impostermodel/wsdl.go b/internal/impostermodel/wsdl.go new file mode 100644 index 0000000..b4e4f38 --- /dev/null +++ b/internal/impostermodel/wsdl.go @@ -0,0 +1,46 @@ +package impostermodel + +import ( + wsdlparser "github.com/outofcoffee/go-wsdl-parser" +) + +func writeWsdlMockConfig(wsdlFilePath string, generateResources bool, forceOverwrite bool, scriptEngine ScriptEngine, scriptFileName string) { + var resources []Resource + if generateResources { + resources = buildWsdlResources(wsdlFilePath, scriptEngine, scriptFileName) + } else { + logger.Debug("skipping resource generation") + } + options := ConfigGenerationOptions{ + PluginName: "soap", + ScriptEngine: scriptEngine, + ScriptFileName: scriptFileName, + WSDLFilePath: wsdlFilePath, + } + writeMockConfigAdjacent(wsdlFilePath, resources, forceOverwrite, options) +} + +func buildWsdlResources(wsdlFilePath string, scriptEngine ScriptEngine, scriptFileName string) []Resource { + parser, err := wsdlparser.NewWSDLParser(wsdlFilePath) + if err != nil { + logger.Fatalf("unable to parse WSDL file: %v: %v", wsdlFilePath, err) + } + + var resources []Resource + for _, op := range parser.GetOperations() { + resource := Resource{ + Method: "POST", + Operation: op.Name, + Response: &ResponseConfig{ + StatusCode: 200, + }, + } + if IsScriptEngineEnabled(scriptEngine) { + resource.Response.ScriptFile = scriptFileName + } + resources = append(resources, resource) + } + + logger.Debugf("generated %d resources from WSDL", len(resources)) + return resources +} diff --git a/internal/wsdl/discovery.go b/internal/wsdl/discovery.go new file mode 100644 index 0000000..36af080 --- /dev/null +++ b/internal/wsdl/discovery.go @@ -0,0 +1,20 @@ +package wsdl + +import ( + "gatehill.io/imposter/internal/fileutil" + "path/filepath" +) + +// DiscoverWSDLFiles finds WSDL files within the given directory. +// It returns fully qualified paths to the files discovered. +func DiscoverWSDLFiles(configDir string) []string { + var wsdlFiles []string + + candidates := fileutil.FindFilesWithExtension(configDir, ".wsdl") + for _, candidate := range candidates { + fullyQualifiedPath := filepath.Join(configDir, candidate) + wsdlFiles = append(wsdlFiles, fullyQualifiedPath) + } + + return wsdlFiles +} From d717ff911e3d7baac07c45f0716912bd6532ae32 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 31 Mar 2026 20:49:05 +0000 Subject: [PATCH 2/3] chore: update go-wsdl-parser to published v0.1.0 Replace local replace directive with published tagged version v0.1.0. https://claude.ai/code/session_01Xsiik4SZGtBrKQi7LxKtXZ --- go.mod | 10 ++++------ go.sum | 8 ++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index e814987..e269427 100644 --- a/go.mod +++ b/go.mod @@ -15,14 +15,14 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.9.1 github.com/spf13/viper v1.19.0 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 gopkg.in/yaml.v2 v2.4.0 sigs.k8s.io/yaml v1.6.0 ) require ( - github.com/antchfx/xmlquery v1.4.4 // indirect - github.com/antchfx/xpath v1.3.4 // indirect + github.com/antchfx/xmlquery v1.5.1 // indirect + github.com/antchfx/xpath v1.3.6 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect golang.org/x/net v0.42.0 // indirect ) @@ -59,7 +59,7 @@ require ( github.com/olekukonko/ll v0.0.9 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect - github.com/outofcoffee/go-wsdl-parser v0.0.0 + github.com/outofcoffee/go-wsdl-parser v0.1.0 github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect @@ -95,5 +95,3 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect ) - -replace github.com/outofcoffee/go-wsdl-parser => /home/user/go-wsdl-parser diff --git a/go.sum b/go.sum index 2e8d6bd..3dc0c04 100644 --- a/go.sum +++ b/go.sum @@ -4,9 +4,13 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/antchfx/xmlquery v1.4.4 h1:mxMEkdYP3pjKSftxss4nUHfjBhnMk4imGoR96FRY2dg= github.com/antchfx/xmlquery v1.4.4/go.mod h1:AEPEEPYE9GnA2mj5Ur2L5Q5/2PycJ0N9Fusrx9b12fc= +github.com/antchfx/xmlquery v1.5.1 h1:T9I4Ns1EXiWHy0IqKupGhnfTQtJwlGrpXtauYOoNv78= +github.com/antchfx/xmlquery v1.5.1/go.mod h1:bVqnl7TaDXSReKINrhZz+2E/PbCu2tUahb+wZ7WZNT8= github.com/antchfx/xpath v1.3.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/antchfx/xpath v1.3.4 h1:1ixrW1VnXd4HurCj7qnqnR0jo14g8JMe20Fshg1Vgz4= github.com/antchfx/xpath v1.3.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= +github.com/antchfx/xpath v1.3.6 h1:s0y+ElRRtTQdfHP609qFu0+c6bglDv20pqOViQjjdPI= +github.com/antchfx/xpath v1.3.6/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA= github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw= github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ= @@ -108,6 +112,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/outofcoffee/go-wsdl-parser v0.1.0 h1:N5kq6AYg9uXQKnnqWGVRtQf+XFE0823eAycNRxK5C6g= +github.com/outofcoffee/go-wsdl-parser v0.1.0/go.mod h1:x5iZZ/j5mDTxplPi1gjLD84+r5wjTeyrHNg+OKyzdPs= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -158,6 +164,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= From 649dca0e184991a2410aeeeebea128de3e96c683 Mon Sep 17 00:00:00 2001 From: Pete Cornish Date: Wed, 1 Apr 2026 20:54:12 +0100 Subject: [PATCH 3/3] feat: update documentation to mention WSDL scaffolding --- README.md | 4 ++-- cmd/scaffold.go | 2 +- cmd/up.go | 2 +- docs/config.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 848c828..956cacb 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ Usage: Available Commands: up Start live mocks of APIs - scaffold Create Imposter configuration from OpenAPI specs + scaffold Create Imposter configuration from OpenAPI specs and WSDL files engine pull Pull the engine into the cache engine list List the engines in the cache doctor Check prerequisites for running Imposter @@ -150,7 +150,7 @@ Flags: -p, --port int Port on which to listen (default 8080) --pull Force engine pull -r, --recursive-config-scan Scan for config files in subdirectories (default false) - -s, --scaffold Scaffold Imposter configuration for all OpenAPI files + -s, --scaffold Scaffold Imposter configuration for all OpenAPI and WSDL files -v, --version string Imposter engine version (default "latest") ``` diff --git a/cmd/scaffold.go b/cmd/scaffold.go index eb2a6e9..4b36870 100644 --- a/cmd/scaffold.go +++ b/cmd/scaffold.go @@ -55,7 +55,7 @@ If DIR is not specified, the current working directory is used.`, func init() { scaffoldCmd.Flags().BoolVarP(&scaffoldFlags.forceOverwrite, "force-overwrite", "f", false, "Force overwrite of destination file(s) if already exist") - scaffoldCmd.Flags().BoolVar(&scaffoldFlags.generateResources, "generate-resources", true, "Generate Imposter resources from OpenAPI paths") + scaffoldCmd.Flags().BoolVar(&scaffoldFlags.generateResources, "generate-resources", true, "Generate Imposter resources from OpenAPI paths or WSDL operations") scaffoldCmd.Flags().StringVarP(&scaffoldFlags.scriptEngine, "script-engine", "s", "none", "Generate placeholder Imposter script (none|groovy|js)") rootCmd.AddCommand(scaffoldCmd) } diff --git a/cmd/up.go b/cmd/up.go index ed87401..7b96830 100644 --- a/cmd/up.go +++ b/cmd/up.go @@ -121,7 +121,7 @@ func init() { upCmd.Flags().IntVarP(&upFlags.port, "port", "p", 8080, "Port on which to listen") upCmd.Flags().BoolVar(&upFlags.forcePull, "pull", false, "Force engine pull") upCmd.Flags().BoolVar(&upFlags.restartOnChange, "auto-restart", true, "Automatically restart when config dir contents change") - upCmd.Flags().BoolVarP(&upFlags.scaffoldMissing, "scaffold", "s", false, "Scaffold Imposter configuration for all OpenAPI files") + upCmd.Flags().BoolVarP(&upFlags.scaffoldMissing, "scaffold", "s", false, "Scaffold Imposter configuration for all OpenAPI and WSDL files") upCmd.Flags().StringVar(&upFlags.deduplicate, "deduplicate", "", "Override deduplication ID for replacement of containers") upCmd.Flags().BoolVar(&upFlags.enablePlugins, "enable-plugins", true, "Enable plugins") upCmd.Flags().BoolVar(&upFlags.ensurePlugins, "install-default-plugins", true, "Install missing default plugins") diff --git a/docs/config.md b/docs/config.md index b635320..83efdf3 100644 --- a/docs/config.md +++ b/docs/config.md @@ -28,7 +28,7 @@ Flags: -p, --port int Port on which to listen (default 8080) --pull Force engine pull -r, --recursive-config-scan Scan for config files in subdirectories (default false) - -s, --scaffold Scaffold Imposter configuration for all OpenAPI files + -s, --scaffold Scaffold Imposter configuration for all OpenAPI and WSDL files -v, --version string Imposter engine version (default "latest") ```