Re: [Catalyst] RESTful client
Tomas Doran wrote: On 4 Dec 2009, at 00:25, Sungsam Gong wrote: OK, let me just clarify my question to narrow down the problem. How does your catalyst application consume remote web services, especially for RESTful? As noted, if at all possible, I don't consume them direct from my application (due to latency and availability issues) If one can't avoid consuming them, then using Time::Hires's ualarm allows sub-second bailing if the remote call takes too long. I too, at $work, want to stop runtime REST calls, but we're paid up with $remote_provider for a few more months. Cheers, David ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] testing catalyst app - need context
Ian Docherty wrote: Kate Yoak wrote: Hi there, Here is a newbie question: I like to test my functionality in bits and pieces as I write it. How do I go about getting myself the context object in a test script? For example, one of the tests catalyst installs is t/model_App.t where it loads the model. I'd love to then be able to use the model the same way a controller would: my $acc = $c-model('Account')-find(1); Instead, I am doing my $model = MyApp::Model::App-new(); my $acc = $model-recordset('Account')-find(1); In addition to being less than ideal because I am doing something different that I expect real application code to do, it presents configuration problems. Like, turns out, in order for config to take effect, I have to run __PACKAGE__-setup; after configuring it - which won't be necessary, I think, in a real app. Is the practice of unit tests that break up the layers of catalyst frowned upon? Or what should I do to make it work right? Best practice is to keep your model separate from Catalyst so that you can (for example) create batch scripts or cron jobs that work on the model without having to load the whole of Catalyst Your model then would be in something like MyApp::Storage and accessed by your tests as so... my $schema = MyApp::Storage-connect( 'DBI:mysql:host=localhost;database=my_database', 'username', 'password', { 'mysql_enable_utf8' = 1 }, {on_connect_do =[ 'set names utf8' ] } ); my $acc = $schema-resultset('Account')-find(1); You would be testing your database layer separately from Catalyst. Models aren't necessarily database layers. I'd suggest that with a sufficiently rich Catalyst application, the 'model' as known by Catalyst could easily become an effective 'controller' of a further model. That secondary controller is going to want to load model classes, and Catalyst provides a nice way of controlling instantiation. e.g. sub handle_payment : Path { my ($self, $c, @args) = @_; my $proc = $c-model('PaymentProcessor'); my $result = $proc-pay( { currency = $args[0], amount = $args[1], id = $args[2] } ); $c-stash-{result}-{message} = $result-message; $c-stash-{result}-{code} = $result-code; } # then, within PaymentProcessor sub pay { my ($self, $args) = @_; MyApp-model( 'Ledger' )-insert( { # blah } ); MyApp-model('Order')-update( { # blah } ) ; } This definitely does tightly couple the PaymentProcessor to the application. However, it also allows for better whitebox testing. If your logic is embedded within a Catalyst controller, the only sensible way to test it is to make an HTTP request. If it's in the model, the individual steps can be tested. FWIW, the principle here is Catalyst controllers should do nothing except validate and translate HTTP parameters to 'model' parameters. They shouldn't manipulate model objects, or build complicated logic by combinations of model calls. Regards, David ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] testing catalyst app - need context
J. Shirley wrote: On Mon, Mar 2, 2009 at 5:00 AM, David Wright dave-catal...@dexy.org mailto:dave-catal...@dexy.org wrote: Ian Docherty wrote: Kate Yoak wrote: Hi there, Here is a newbie question: I like to test my functionality in bits and pieces as I write it. How do I go about getting myself the context object in a test script? For example, one of the tests catalyst installs is t/model_App.t where it loads the model. I'd love to then be able to use the model the same way a controller would: my $acc = $c-model('Account')-find(1); Instead, I am doing my $model = MyApp::Model::App-new(); my $acc = $model-recordset('Account')-find(1); In addition to being less than ideal because I am doing something different that I expect real application code to do, it presents configuration problems. Like, turns out, in order for config to take effect, I have to run __PACKAGE__-setup; after configuring it - which won't be necessary, I think, in a real app. Is the practice of unit tests that break up the layers of catalyst frowned upon? Or what should I do to make it work right? Best practice is to keep your model separate from Catalyst so that you can (for example) create batch scripts or cron jobs that work on the model without having to load the whole of Catalyst Your model then would be in something like MyApp::Storage and accessed by your tests as so... my $schema = MyApp::Storage-connect( 'DBI:mysql:host=localhost;database=my_database', 'username', 'password', { 'mysql_enable_utf8' = 1 }, {on_connect_do =[ 'set names utf8' ] } ); my $acc = $schema-resultset('Account')-find(1); You would be testing your database layer separately from Catalyst. Models aren't necessarily database layers. I'd suggest that with a sufficiently rich Catalyst application, the 'model' as known by Catalyst could easily become an effective 'controller' of a further model. That secondary controller is going to want to load model classes, and Catalyst provides a nice way of controlling instantiation. e.g. sub handle_payment : Path { my ($self, $c, @args) = @_; my $proc = $c-model('PaymentProcessor'); my $result = $proc-pay( { currency = $args[0], amount = $args[1], id = $args[2] } ); $c-stash-{result}-{message} = $result-message; $c-stash-{result}-{code} = $result-code; } # then, within PaymentProcessor sub pay { my ($self, $args) = @_; MyApp-model( 'Ledger' )-insert( { # blah } ); MyApp-model('Order')-update( { # blah } ) ; } This definitely does tightly couple the PaymentProcessor to the application. However, it also allows for better whitebox testing. If your logic is embedded within a Catalyst controller, the only sensible way to test it is to make an HTTP request. If it's in the model, the individual steps can be tested. FWIW, the principle here is Catalyst controllers should do nothing except validate and translate HTTP parameters to 'model' parameters. They shouldn't manipulate model objects, or build complicated logic by combinations of model calls. Regards, David It's good advice to have things standalone and available outside of Catalyst, but your assessment of model dependencies stops short. What you want is an independent model that accepts a schema object for recording, and then a very thin adapter class inside of Catalyst. And the config object, cache backends, the logger? The code above could be made more complex: sub pay { my ($self, $args) = @_; my $order = MyApp-cache('ordercache')-get( $args{id} ) || do { my $o = MyApp-model('Order')-find( $args{id} ) ; MyApp-cache('ordercache')-set( $o-id, $o, MyApp-config-{cache_expiry}); $o; }; $o-update( { #blah } ); MyApp-log-debug (Got order); MyApp-model( 'Ledger' )-insert( { # blah } ); } As I said, this 'model' class is very controller-like. Something has to deal with the interactions between those components, and I contend that it shouldn't be a standard Catalyst controller. Using something like this is the suggested better practice: package MyApp::Model::PaymentProcessor; use base 'Catalyst::Model::Adaptor'; __PACKAGE__-config( class = 'MyApp::PaymentProcessor' ); sub prepare_arguments { my ($self, $c) = @_; return { log = $c-log, expiry = $c-config-{cache_expiry}, cache = $c-cache, schema = $c-model-schema }; } But this doesn't help much: now, when testing
Re: [Catalyst] Maybe there is a need for some speedups of 'config' method ?
Jonathan Rockway wrote: * On Mon, Feb 23 2009, Jason Gottshall wrote: Oleg Pronin wrote: I use many actions that take params from config in runtime, for example sub pay_for_vip : Private { ... my $price = $c-cfg-{vip}{price}; } As I understand it, this is NOT the way config is intended to work. All the config for your component (controller in this case) is passed to the constructor at setup time; all you need to do is make accessors for whatever you want access to: __PACKAGE__-mk_accessors(qw/vip/); sub pay_for_vip : Private { ... my $price = $self-vip-{price}; } Yes, exactly. This is another case of the all-too-frequent change Catalyst so that I won't have to change any code in my poorly-implemented app. Jeez. That's a little harsh, though I sympathise with the general point. We use the Catalyst config file to initialize Catalyst components, to initialise non-Catalyst configuration objects, and also to provide via config() a simple runtime interface to 'get this key/value pair'. We store other (runtime) conf values in the db, wrapped with memcached, to avoid having to deploy a config file if we need timely changes. Many of our conf values are shared between components, not directly relevant to components, or are most readably kept together as a discrete configuration set, rather than added per component. Finally, given the size of our conf file, I don't think we'd want to clutter either our packages with accessors, or our project with classes that merely wrap configuration sets. I don't think the patch will be harmful, though, so if there is one we might as well apply it. But it's a lot easier to not misuse config than it is to patch Catalyst to make the misuse faster. I can't see anywhere in the docs where this 'intended use' is stated. That's not to say that it isn't there. Having said all that, our app must call config 10s of million times a day, and we've never perceived it to be a bottleneck. Regards, David ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] RFC: The paradox of choice in web development
I can't say much because of confidentiality, but from the Catalyst survey late last year, I can say that there are some pretty high profile places using Catalyst around about. It's public knowledge that two of the biggest streaming media websites in the world use Catalyst. Aye, that it is: http://www.bbc.co.uk/blogs/bbcinternet/2008/12/iplayer_day_performance_tricks.html David ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Testing RESTful web services
Ian Docherty wrote: Moritz Onken wrote: Am 05.10.2008 um 10:47 schrieb Ian Docherty: Hi I am writing a simple test to test a POST method in a web service but my controller does not see any content in the POSTed request. In the controller both the $c-request-body and $c-request-content_length are undefined. Any ideas? -- test.t --- use strict; use warnings; use Catalyst::Test 'MyApp'; use HTTP::Request; my $req = HTTP::Request-new( 'POST', '/foo', [ Content_Type = 'text/plain' ], hello world, ); It's Content-type = ... Yup, typo on my part, but it does not change the problem. There is still no content in the request when it gets to the controller. It's not a typo, the constructor accepts underscores as well as dashes so that you can build requests without having to quote the hash keys. Just a slight modification to my original statement. In the controller the request body is undef, but the request length is 0 (not undef) IIRC you have to manually add content-length yourself, HTTP::Request doesn't build it for you. Regards, David ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Catalyst::Log::Log4perl autoflush
J. Shirley wrote: On Sat, Apr 19, 2008 at 8:01 AM, David Wright [EMAIL PROTECTED] wrote: Hi, It seems that 'autoflush' doesn't mean what it usually does in Catalyst::Log::Log4perl. It usually means that a write should happen immediately, and not be buffered. That isn't the behaviour in Catalyst::Log::Log4perl, either when set using the log4perl conf, or when using the option to new(). The option to new() disables 'abort', which I think is a misunderstanding. The logging functions always simply push to the log4perlstack, which is only flushed after the request has been mostly handled. In order to get autoflush working as expected, I have had to create a derived class and override _log(): sub _log { my $self = shift; $self-SUPER::_log(@_); $self-_flush if scalar(caller(1)) =~ /^MyApp(::|$)/; } perl -v: v5.8.8 built for i486-linux-gnu-thread-multi uname -a: Linux PC-5023452 2.6.22-14-generic #1 SMP Fri Feb 1 04:59:50 UTC 2008 i686 GNU/Linux Catalyst::Log::Log4perl version: 1.0 I've raised a bug in RT for this: http://rt.cpan.org/Public/Bug/Display.html?id=35221 Thanks, David Wright David, Could you throw a test case in with this (either on the RT bug or in this mail) and I'll get a patch put in place? Diff to 10-basic.t attached. Cheers, David 6c6 use Test::More tests = 14; --- use Test::More tests = 15; 91a92,106 # check that if autoflush is enabled, the log is written to immediately $app-log( Catalyst::Log::Log4perl-new( \CONF, override_cspecs = 1, autoflush = 1 ) ); log4perl.rootLogger=WARN, LOG log4perl.appender.LOG=Log::Log4perl::Appender::String log4perl.appender.LOG.layout=PatternLayout log4perl.appender.LOG.layout.ConversionPattern=[%c] %m CONF $appender-layout( Log::Log4perl::Layout::PatternLayout-new('%m') ); $c = $app-log-warn('delay'); log_like( qr|delay|, autoflush ); ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
[Catalyst] Catalyst::Log::Log4perl autoflush
Hi, It seems that 'autoflush' doesn't mean what it usually does in Catalyst::Log::Log4perl. It usually means that a write should happen immediately, and not be buffered. That isn't the behaviour in Catalyst::Log::Log4perl, either when set using the log4perl conf, or when using the option to new(). The option to new() disables 'abort', which I think is a misunderstanding. The logging functions always simply push to the log4perlstack, which is only flushed after the request has been mostly handled. In order to get autoflush working as expected, I have had to create a derived class and override _log(): sub _log { my $self = shift; $self-SUPER::_log(@_); $self-_flush if scalar(caller(1)) =~ /^MyApp(::|$)/; } perl -v: v5.8.8 built for i486-linux-gnu-thread-multi uname -a: Linux PC-5023452 2.6.22-14-generic #1 SMP Fri Feb 1 04:59:50 UTC 2008 i686 GNU/Linux Catalyst::Log::Log4perl version: 1.0 I've raised a bug in RT for this: http://rt.cpan.org/Public/Bug/Display.html?id=35221 Thanks, David Wright ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Catalyst::Log::Log4perl autoflush
It seems that 'autoflush' doesn't mean what it usually does in Catalyst::Log::Log4perl. It usually means that a write should happen immediately, and not be buffered. That isn't the behaviour in Catalyst::Log::Log4perl, either when set using the log4perl conf, or when using the option to new(). The option to new() disables 'abort', which I think is a misunderstanding. The logging functions always simply push to the log4perlstack, which is only flushed after the request has been mostly handled. In order to get autoflush working as expected, I have had to create a derived class and override _log(): sub _log { my $self = shift; $self-SUPER::_log(@_); $self-_flush if scalar(caller(1)) =~ /^MyApp(::|$)/; } perl -v: v5.8.8 built for i486-linux-gnu-thread-multi uname -a: Linux PC-5023452 2.6.22-14-generic #1 SMP Fri Feb 1 04:59:50 UTC 2008 i686 GNU/Linux Catalyst::Log::Log4perl version: 1.0 I've raised a bug in RT for this: http://rt.cpan.org/Public/Bug/Display.html?id=35221 David, Could you throw a test case in with this (either on the RT bug or in this mail) and I'll get a patch put in place? Hello Jay, Which of the autoflushes should I test against: the parameter to new(), or the option in a log4perl configuration file? Do you (or others) agree that the autoflush option to new() is a misnomer? If not, wouldn't my test simply prove that the code doesn't do what it doesn't say it does? David ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] fix config right before database connect?
Hi, Hello! I'm running several instances of Catalyst app (for every developer and production) on the same box; I'm thinking of automatically patch database name loaded from config file to allow separate copies of databases to coexist transparently. We have the same multi-instance set up, and instead of patching have two config files per instance. The first contains entries common to all, and the second adds in instance specific database connect info. Catalyst will load any config named $myapp_foo. In this case, I doubt the order matters. e.g. cat conf/myapp_common.xml config nameMyapp/name logconf/logging.conf/log model name=Core schema_classMyapp::Schema::DB/schema_class /model /config cat conf/myapp_perinstance.xml config nameMyapp/name model name=Core connect_infodsn:blah/connect_info connect_infomonkey/connect_info connect_infotennis/connect_info /model /config HTH, David ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/